<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <meta name="generator" content="VuePress 2.0.0-beta.60">
    <script>
      (function() {
        const userMode = localStorage.getItem('vuepress-reco-color-scheme') || 'auto';
        const systemDarkMode = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;

        if (userMode === 'dark' || (userMode === 'auto' && systemDarkMode)) {
          document.documentElement.classList.toggle('dark', true);
        }
      })();
    </script>
    <title>Redis 内存数据库 | 阿派 | Apai Blog</title><meta name="description" content="Just playing around">
    <link rel="modulepreload" href="/assets/app-8a43a0f0.js"><link rel="modulepreload" href="/assets/framework-e1bed10d.js"><link rel="modulepreload" href="/assets/Redis.html-aa5c160a.js"><link rel="modulepreload" href="/assets/Redis.html-f7a014e9.js"><link rel="prefetch" href="/assets/index.html-ef2f4f01.js" as="script"><link rel="prefetch" href="/assets/index.html-1013d654.js" as="script"><link rel="prefetch" href="/assets/index.html-a146dedc.js" as="script"><link rel="prefetch" href="/assets/index.html-f4b2eaea.js" as="script"><link rel="prefetch" href="/assets/index.html-e3ed352e.js" as="script"><link rel="prefetch" href="/assets/index.html-42ce2ab9.js" as="script"><link rel="prefetch" href="/assets/index.html-ec24ec9e.js" as="script"><link rel="prefetch" href="/assets/index.html-d3d8d7ce.js" as="script"><link rel="prefetch" href="/assets/index.html-9faf073b.js" as="script"><link rel="prefetch" href="/assets/index.html-9364b7dd.js" as="script"><link rel="prefetch" href="/assets/index.html-fc0fb462.js" as="script"><link rel="prefetch" href="/assets/index.html-603c6c19.js" as="script"><link rel="prefetch" href="/assets/index.html-0349deb8.js" as="script"><link rel="prefetch" href="/assets/index.html-09405a87.js" as="script"><link rel="prefetch" href="/assets/index.html-91577c59.js" as="script"><link rel="prefetch" href="/assets/index.html-552ae255.js" as="script"><link rel="prefetch" href="/assets/index.html-424369c4.js" as="script"><link rel="prefetch" href="/assets/index.html-1dfc0069.js" as="script"><link rel="prefetch" href="/assets/index.html-ec62f595.js" as="script"><link rel="prefetch" href="/assets/index.html-4621ef22.js" as="script"><link rel="prefetch" href="/assets/index.html-e189ec13.js" as="script"><link rel="prefetch" href="/assets/index.html-b424a45b.js" as="script"><link rel="prefetch" href="/assets/index.html-623952a8.js" as="script"><link rel="prefetch" href="/assets/index.html-cedcb7c8.js" as="script"><link rel="prefetch" href="/assets/index.html-07f61d2f.js" as="script"><link rel="prefetch" href="/assets/index.html-9ef01f1e.js" as="script"><link rel="prefetch" href="/assets/index.html-dfa6d19f.js" as="script"><link rel="prefetch" href="/assets/index.html-23dd0955.js" as="script"><link rel="prefetch" href="/assets/index.html-1e7a4ff3.js" as="script"><link rel="prefetch" href="/assets/index.html-e12f154a.js" as="script"><link rel="prefetch" href="/assets/index.html-30de2d02.js" as="script"><link rel="prefetch" href="/assets/index.html-6a244983.js" as="script"><link rel="prefetch" href="/assets/index.html-8900b10e.js" as="script"><link rel="prefetch" href="/assets/index.html-b3210461.js" as="script"><link rel="prefetch" href="/assets/biaoqian-fenlei-moban.html-2db9524d.js" as="script"><link rel="prefetch" href="/assets/MuBan-Apai.html-5af383c8.js" as="script"><link rel="prefetch" href="/assets/guide.html-5aaed80e.js" as="script"><link rel="prefetch" href="/assets/Lu-aboutMe.html-82ee5401.js" as="script"><link rel="prefetch" href="/assets/kaishi.html-9d8493a0.js" as="script"><link rel="prefetch" href="/assets/Hobby-SheYing.html-3ac28a1b.js" as="script"><link rel="prefetch" href="/assets/Lu-aboutMe.html-96d10c31.js" as="script"><link rel="prefetch" href="/assets/Work-MaYun.html-5e497e8c.js" as="script"><link rel="prefetch" href="/assets/Java-basics.html-4a44925e.js" as="script"><link rel="prefetch" href="/assets/JavaAPI.html-ae8a1843.js" as="script"><link rel="prefetch" href="/assets/JavaBiKeng04.html-c9e75b16.js" as="script"><link rel="prefetch" href="/assets/JavaGongNeng03.html-6ca97faf.js" as="script"><link rel="prefetch" href="/assets/JavaJinJie02.html-eaabb81d.js" as="script"><link rel="prefetch" href="/assets/JavaMyUtil.html-e2cff404.js" as="script"><link rel="prefetch" href="/assets/MyBatisPlus.html-b608a85b.js" as="script"><link rel="prefetch" href="/assets/MySql.html-4bcdc408.js" as="script"><link rel="prefetch" href="/assets/MySqlFunction.html-23affe6f.js" as="script"><link rel="prefetch" href="/assets/RabbitMQ.html-2cc19b22.js" as="script"><link rel="prefetch" href="/assets/ShiWuAffair.html-33f5c0c4.js" as="script"><link rel="prefetch" href="/assets/Spring.html-628746d6.js" as="script"><link rel="prefetch" href="/assets/SpringConfig.html-49f3c621.js" as="script"><link rel="prefetch" href="/assets/SpringPeiZhi.html-ac6df88a.js" as="script"><link rel="prefetch" href="/assets/SpringSecurity.html-057633f1.js" as="script"><link rel="prefetch" href="/assets/WebSocket.html-57d6fc97.js" as="script"><link rel="prefetch" href="/assets/DockerCompose.html-98ad6b52.js" as="script"><link rel="prefetch" href="/assets/Linux.html-43351365.js" as="script"><link rel="prefetch" href="/assets/Nginx.html-f1276de6.js" as="script"><link rel="prefetch" href="/assets/RabbitMQ_COPY.html-5cdb6370.js" as="script"><link rel="prefetch" href="/assets/Redis_COPY.html-486e1d26.js" as="script"><link rel="prefetch" href="/assets/Redis_CRUD.html-47e0af0f.js" as="script"><link rel="prefetch" href="/assets/BatJiaoBen.html-d2d2666a.js" as="script"><link rel="prefetch" href="/assets/DmShengChen.html-bb069d8e.js" as="script"><link rel="prefetch" href="/assets/EasyExcel.html-b1eb613d.js" as="script"><link rel="prefetch" href="/assets/GitLu.html-eae89aa5.js" as="script"><link rel="prefetch" href="/assets/JavaKaiFa.html-4fbb86cc.js" as="script"><link rel="prefetch" href="/assets/JSR303.html-b976b418.js" as="script"><link rel="prefetch" href="/assets/MinIO.html-5e3d4702.js" as="script"><link rel="prefetch" href="/assets/ShardingJDBC.html-d0f811b3.js" as="script"><link rel="prefetch" href="/assets/Swagger.html-bb111a21.js" as="script"><link rel="prefetch" href="/assets/Vuepress.html-994cf672.js" as="script"><link rel="prefetch" href="/assets/Angular.html-3115afab.js" as="script"><link rel="prefetch" href="/assets/ElementUI.html-35bc6477.js" as="script"><link rel="prefetch" href="/assets/Html-Js.html-015f1806.js" as="script"><link rel="prefetch" href="/assets/Vue-basics.html-a64846f4.js" as="script"><link rel="prefetch" href="/assets/Vue3_group.html-f53be77f.js" as="script"><link rel="prefetch" href="/assets/Vue3_option.html-19f76b9e.js" as="script"><link rel="prefetch" href="/assets/ApifoxAPIceshi.html-19cd8153.js" as="script"><link rel="prefetch" href="/assets/PDManeryuanshujianmo.html-f6fa9d9e.js" as="script"><link rel="prefetch" href="/assets/OCRwenzishibie.html-11fc474d.js" as="script"><link rel="prefetch" href="/assets/EasyExcelbiaogeku.html-30777927.js" as="script"><link rel="prefetch" href="/assets/Javadaimashengchengqi.html-cf566ce0.js" as="script"><link rel="prefetch" href="/assets/JDKshuangbanben.html-1f259d3b.js" as="script"><link rel="prefetch" href="/assets/JSR303canshuxiaoyan.html-78322130.js" as="script"><link rel="prefetch" href="/assets/Mail  youjian.html-7e3a0f69.js" as="script"><link rel="prefetch" href="/assets/MyBatisPlusxiangjie.html-0168c152.js" as="script"><link rel="prefetch" href="/assets/MySQLzhucongfuzhi.html-7a4739e8.js" as="script"><link rel="prefetch" href="/assets/Redis-API.html-f488940c.js" as="script"><link rel="prefetch" href="/assets/SpringBootshiwu.html-c07a3864.js" as="script"><link rel="prefetch" href="/assets/SpringBootduxiefenli.html-f0993780.js" as="script"><link rel="prefetch" href="/assets/Springguolvqihelanjieqi.html-78feb321.js" as="script"><link rel="prefetch" href="/assets/WebSocket.html-caecf367.js" as="script"><link rel="prefetch" href="/assets/quanjuyichang-JSR303.html-add01eff.js" as="script"><link rel="prefetch" href="/assets/Docker.html-14746447.js" as="script"><link rel="prefetch" href="/assets/Dockeryuanchengfangwenbushu.html-7dc4f8d3.js" as="script"><link rel="prefetch" href="/assets/Nginxfanxiangdaili.html-42533685.js" as="script"><link rel="prefetch" href="/assets/Apai-SheYingOne.html-143bc574.js" as="script"><link rel="prefetch" href="/assets/Apai-Year.html-b713587f.js" as="script"><link rel="prefetch" href="/assets/My2305.html-b224c5e2.js" as="script"><link rel="prefetch" href="/assets/My2306.html-94838726.js" as="script"><link rel="prefetch" href="/assets/My2307.html-df2118c4.js" as="script"><link rel="prefetch" href="/assets/My2308.html-396c79bc.js" as="script"><link rel="prefetch" href="/assets/My2309.html-1ebdc4bb.js" as="script"><link rel="prefetch" href="/assets/My2310.html-d4ffbd04.js" as="script"><link rel="prefetch" href="/assets/My2311.html-30f23133.js" as="script"><link rel="prefetch" href="/assets/My2312.html-2da62191.js" as="script"><link rel="prefetch" href="/assets/Yi-HuBei.html-90d02bf7.js" as="script"><link rel="prefetch" href="/assets/Yi-ZhuHai.html-e202f6fb.js" as="script"><link rel="prefetch" href="/assets/Apache ECharts tubiao.html-6d4a4703.js" as="script"><link rel="prefetch" href="/assets/Vue3 zuheshi API.html-9fe2887f.js" as="script"><link rel="prefetch" href="/assets/Vue3 xuanxiangshi API.html-d584c181.js" as="script"><link rel="prefetch" href="/assets/Vue3-i18n-guojihuachajian.html-16f6e650.js" as="script"><link rel="prefetch" href="/assets/Batpichulijiaoben.html-307223b0.js" as="script"><link rel="prefetch" href="/assets/Gitgongzuoliu.html-fa6e129f.js" as="script"><link rel="prefetch" href="/assets/Typoratuchuang.html-22c57156.js" as="script"><link rel="prefetch" href="/assets/Vuepress.html-df146bdb.js" as="script"><link rel="prefetch" href="/assets/My2401.html-49f6440f.js" as="script"><link rel="prefetch" href="/assets/My2402.html-950d4e85.js" as="script"><link rel="prefetch" href="/assets/shenhai-0509.html-2007281b.js" as="script"><link rel="prefetch" href="/assets/zhuhaixing.html-17db8380.js" as="script"><link rel="prefetch" href="/assets/404.html-f9875e7b.js" as="script"><link rel="prefetch" href="/assets/index.html-40bced6f.js" as="script"><link rel="prefetch" href="/assets/index.html-3c78780e.js" as="script"><link rel="prefetch" href="/assets/index.html-ef51ba1b.js" as="script"><link rel="prefetch" href="/assets/index.html-bdec80a5.js" as="script"><link rel="prefetch" href="/assets/index.html-3b5427f8.js" as="script"><link rel="prefetch" href="/assets/index.html-cbd49540.js" as="script"><link rel="prefetch" href="/assets/index.html-b0b97c81.js" as="script"><link rel="prefetch" href="/assets/index.html-2793d245.js" as="script"><link rel="prefetch" href="/assets/index.html-71d9a5d9.js" as="script"><link rel="prefetch" href="/assets/index.html-4e7d77cd.js" as="script"><link rel="prefetch" href="/assets/index.html-aeace11a.js" as="script"><link rel="prefetch" href="/assets/index.html-c62ed802.js" as="script"><link rel="prefetch" href="/assets/index.html-e640d31f.js" as="script"><link rel="prefetch" href="/assets/index.html-48e1c605.js" as="script"><link rel="prefetch" href="/assets/index.html-385dcb56.js" as="script"><link rel="prefetch" href="/assets/index.html-1bb1a523.js" as="script"><link rel="prefetch" href="/assets/index.html-1ed80e8d.js" as="script"><link rel="prefetch" href="/assets/index.html-2c154a45.js" as="script"><link rel="prefetch" href="/assets/index.html-3e93d436.js" as="script"><link rel="prefetch" href="/assets/index.html-2a93e2c9.js" as="script"><link rel="prefetch" href="/assets/index.html-cff07ba3.js" as="script"><link rel="prefetch" href="/assets/index.html-7ec32a34.js" as="script"><link rel="prefetch" href="/assets/index.html-ddb40108.js" as="script"><link rel="prefetch" href="/assets/index.html-40ab6c4f.js" as="script"><link rel="prefetch" href="/assets/index.html-47e4ee8b.js" as="script"><link rel="prefetch" href="/assets/index.html-c15250e1.js" as="script"><link rel="prefetch" href="/assets/index.html-fb2ea2e4.js" as="script"><link rel="prefetch" href="/assets/index.html-d7e5408a.js" as="script"><link rel="prefetch" href="/assets/index.html-a38055d0.js" as="script"><link rel="prefetch" href="/assets/index.html-be4e50cb.js" as="script"><link rel="prefetch" href="/assets/index.html-660e4bef.js" as="script"><link rel="prefetch" href="/assets/index.html-98aa61ea.js" as="script"><link rel="prefetch" href="/assets/index.html-a6b7472f.js" as="script"><link rel="prefetch" href="/assets/index.html-ab78917a.js" as="script"><link rel="prefetch" href="/assets/biaoqian-fenlei-moban.html-f2c6c309.js" as="script"><link rel="prefetch" href="/assets/MuBan-Apai.html-5714876d.js" as="script"><link rel="prefetch" href="/assets/guide.html-9a89b22b.js" as="script"><link rel="prefetch" href="/assets/Lu-aboutMe.html-f8203e0a.js" as="script"><link rel="prefetch" href="/assets/kaishi.html-4ff9d0f3.js" as="script"><link rel="prefetch" href="/assets/Hobby-SheYing.html-e1ab7a00.js" as="script"><link rel="prefetch" href="/assets/Lu-aboutMe.html-4b735204.js" as="script"><link rel="prefetch" href="/assets/Work-MaYun.html-a185f330.js" as="script"><link rel="prefetch" href="/assets/Java-basics.html-c0d3a063.js" as="script"><link rel="prefetch" href="/assets/JavaAPI.html-f75cbb54.js" as="script"><link rel="prefetch" href="/assets/JavaBiKeng04.html-d2fc755d.js" as="script"><link rel="prefetch" href="/assets/JavaGongNeng03.html-c51a3060.js" as="script"><link rel="prefetch" href="/assets/JavaJinJie02.html-e5a66660.js" as="script"><link rel="prefetch" href="/assets/JavaMyUtil.html-6e16ee98.js" as="script"><link rel="prefetch" href="/assets/MyBatisPlus.html-1cafeb7e.js" as="script"><link rel="prefetch" href="/assets/MySql.html-5adc8c86.js" as="script"><link rel="prefetch" href="/assets/MySqlFunction.html-2c432c8c.js" as="script"><link rel="prefetch" href="/assets/RabbitMQ.html-d771200f.js" as="script"><link rel="prefetch" href="/assets/ShiWuAffair.html-ce7fc825.js" as="script"><link rel="prefetch" href="/assets/Spring.html-3d622ed7.js" as="script"><link rel="prefetch" href="/assets/SpringConfig.html-6fe667f9.js" as="script"><link rel="prefetch" href="/assets/SpringPeiZhi.html-96b777da.js" as="script"><link rel="prefetch" href="/assets/SpringSecurity.html-fe792e2f.js" as="script"><link rel="prefetch" href="/assets/WebSocket.html-7fd7be86.js" as="script"><link rel="prefetch" href="/assets/DockerCompose.html-f6ef44c4.js" as="script"><link rel="prefetch" href="/assets/Linux.html-a1058183.js" as="script"><link rel="prefetch" href="/assets/Nginx.html-bf694d87.js" as="script"><link rel="prefetch" href="/assets/RabbitMQ_COPY.html-1e53d902.js" as="script"><link rel="prefetch" href="/assets/Redis_COPY.html-ef853ef3.js" as="script"><link rel="prefetch" href="/assets/Redis_CRUD.html-7a4bb7d5.js" as="script"><link rel="prefetch" href="/assets/BatJiaoBen.html-20ec59d7.js" as="script"><link rel="prefetch" href="/assets/DmShengChen.html-92a2db1f.js" as="script"><link rel="prefetch" href="/assets/EasyExcel.html-ac2c3493.js" as="script"><link rel="prefetch" href="/assets/GitLu.html-27823973.js" as="script"><link rel="prefetch" href="/assets/JavaKaiFa.html-ff11bb84.js" as="script"><link rel="prefetch" href="/assets/JSR303.html-0c745945.js" as="script"><link rel="prefetch" href="/assets/MinIO.html-958125dd.js" as="script"><link rel="prefetch" href="/assets/ShardingJDBC.html-ce0afe07.js" as="script"><link rel="prefetch" href="/assets/Swagger.html-9c9fb3be.js" as="script"><link rel="prefetch" href="/assets/Vuepress.html-4e07419a.js" as="script"><link rel="prefetch" href="/assets/Angular.html-3e716bd5.js" as="script"><link rel="prefetch" href="/assets/ElementUI.html-70835a6c.js" as="script"><link rel="prefetch" href="/assets/Html-Js.html-848bb521.js" as="script"><link rel="prefetch" href="/assets/Vue-basics.html-772005d8.js" as="script"><link rel="prefetch" href="/assets/Vue3_group.html-69369e84.js" as="script"><link rel="prefetch" href="/assets/Vue3_option.html-37ac05d4.js" as="script"><link rel="prefetch" href="/assets/ApifoxAPIceshi.html-0bcb1468.js" as="script"><link rel="prefetch" href="/assets/PDManeryuanshujianmo.html-4c377e02.js" as="script"><link rel="prefetch" href="/assets/OCRwenzishibie.html-b4248616.js" as="script"><link rel="prefetch" href="/assets/EasyExcelbiaogeku.html-511b0f0b.js" as="script"><link rel="prefetch" href="/assets/Javadaimashengchengqi.html-33991c95.js" as="script"><link rel="prefetch" href="/assets/JDKshuangbanben.html-8bba14d4.js" as="script"><link rel="prefetch" href="/assets/JSR303canshuxiaoyan.html-7d12c0ef.js" as="script"><link rel="prefetch" href="/assets/Mail  youjian.html-d520132f.js" as="script"><link rel="prefetch" href="/assets/MyBatisPlusxiangjie.html-94d1940a.js" as="script"><link rel="prefetch" href="/assets/MySQLzhucongfuzhi.html-bf156f04.js" as="script"><link rel="prefetch" href="/assets/Redis-API.html-534cd405.js" as="script"><link rel="prefetch" href="/assets/SpringBootshiwu.html-a83407ed.js" as="script"><link rel="prefetch" href="/assets/SpringBootduxiefenli.html-e50eba32.js" as="script"><link rel="prefetch" href="/assets/Springguolvqihelanjieqi.html-b7cdfd68.js" as="script"><link rel="prefetch" href="/assets/WebSocket.html-7c2b5253.js" as="script"><link rel="prefetch" href="/assets/quanjuyichang-JSR303.html-1f70d8b7.js" as="script"><link rel="prefetch" href="/assets/Docker.html-51026828.js" as="script"><link rel="prefetch" href="/assets/Dockeryuanchengfangwenbushu.html-f42be316.js" as="script"><link rel="prefetch" href="/assets/Nginxfanxiangdaili.html-a98dc972.js" as="script"><link rel="prefetch" href="/assets/Apai-SheYingOne.html-b5b7ae7c.js" as="script"><link rel="prefetch" href="/assets/Apai-Year.html-ce260a3f.js" as="script"><link rel="prefetch" href="/assets/My2305.html-8daa1c69.js" as="script"><link rel="prefetch" href="/assets/My2306.html-893e00c1.js" as="script"><link rel="prefetch" href="/assets/My2307.html-e78450ff.js" as="script"><link rel="prefetch" href="/assets/My2308.html-0e38205b.js" as="script"><link rel="prefetch" href="/assets/My2309.html-06a48ebc.js" as="script"><link rel="prefetch" href="/assets/My2310.html-59afa2c3.js" as="script"><link rel="prefetch" href="/assets/My2311.html-b634eab1.js" as="script"><link rel="prefetch" href="/assets/My2312.html-aafaa08a.js" as="script"><link rel="prefetch" href="/assets/Yi-HuBei.html-61c8ef5d.js" as="script"><link rel="prefetch" href="/assets/Yi-ZhuHai.html-26a46f60.js" as="script"><link rel="prefetch" href="/assets/Apache ECharts tubiao.html-e9cc0012.js" as="script"><link rel="prefetch" href="/assets/Vue3 zuheshi API.html-11ae0fbc.js" as="script"><link rel="prefetch" href="/assets/Vue3 xuanxiangshi API.html-ce744458.js" as="script"><link rel="prefetch" href="/assets/Vue3-i18n-guojihuachajian.html-1fa338e8.js" as="script"><link rel="prefetch" href="/assets/Batpichulijiaoben.html-06ab27bc.js" as="script"><link rel="prefetch" href="/assets/Gitgongzuoliu.html-b1e45d5c.js" as="script"><link rel="prefetch" href="/assets/Typoratuchuang.html-cb5c9b25.js" as="script"><link rel="prefetch" href="/assets/Vuepress.html-c36453a2.js" as="script"><link rel="prefetch" href="/assets/My2401.html-9b16cb88.js" as="script"><link rel="prefetch" href="/assets/My2402.html-3ade37a1.js" as="script"><link rel="prefetch" href="/assets/shenhai-0509.html-648d7d95.js" as="script"><link rel="prefetch" href="/assets/zhuhaixing.html-7d486783.js" as="script"><link rel="prefetch" href="/assets/404.html-7c90b0cc.js" as="script"><link rel="prefetch" href="/assets/reco-valine-a0c1af1f.js" as="script">
    <link rel="preload" href="/assets/style-8a0f09c6.css" as="style"><link rel="stylesheet" href="/assets/style-8a0f09c6.css">
  </head>
  <body>
    <div id="app"><!--[--><div class="theme-container"><div class="common-wrapper show-series show-catalog"><div><header class="navbar-container"><!--[--><div class="site-brand nav-item"><img class="logo" src="/logo.png" alt="阿派 | Apai Blog"><a href="/" class="site-name can-hide">阿派 | Apai Blog</a></div><div class="nav-item navbar-links-wrapper" style=""><form class="search-box" role="search"><input type="search" autocomplete="off" spellcheck="false" value><!----></form><nav class="navbar-links"><!--[--><div class="navbar-links__item"><a href="/" class="link router-link-active" aria-label="Home"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->Home<!--]--></span></span><!--[--><!--]--></a></div><div class="navbar-links__item"><a href="/categories/Java/1/" class="link" aria-label="分类组"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->分类组<!--]--></span></span><!--[--><!--]--></a></div><div class="navbar-links__item"><a href="/tags/Rests/1/" class="link" aria-label="标签组"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->标签组<!--]--></span></span><!--[--><!--]--></a></div><div class="navbar-links__item"><div class="dropdown-link"><button class="dropdown-link__title" type="button" aria-label="文档组"><span class="xicon-container left title"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->文档组<!--]--></span></span><span class="arrow down"></span></button><button class="dropdown-link--mobile__title" type="button" aria-label="文档组"><span class="title"><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->文档组<!--]--></span></span></span><span class="right arrow"></span></button><ul style="display:none;" class="dropdown-link__container"><!--[--><li class="dropdown-link__item"><a href="/docs/Web-develop/Html-Js" class="link" aria-label="Web-开发"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->Web-开发<!--]--></span></span><!--[--><!--]--></a></li><li class="dropdown-link__item"><a href="/docs/Java-develop/JavaMyUtil" class="link" aria-label="Java-开发"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->Java-开发<!--]--></span></span><!--[--><!--]--></a></li><li class="dropdown-link__item"><a href="/docs/Linux-develop/Linux" class="link" aria-label="Linux-系统"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->Linux-系统<!--]--></span></span><!--[--><!--]--></a></li><li class="dropdown-link__item"><a href="/docs/Rests-docs/Vuepress" class="link" aria-label="Apai-其他"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->Apai-其他<!--]--></span></span><!--[--><!--]--></a></li><!--]--></ul></div></div><div class="navbar-links__item"><div class="dropdown-link"><button class="dropdown-link__title" type="button" aria-label="花圃里"><span class="xicon-container left title"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->花圃里<!--]--></span></span><span class="arrow down"></span></button><button class="dropdown-link--mobile__title" type="button" aria-label="花圃里"><span class="title"><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->花圃里<!--]--></span></span></span><span class="right arrow"></span></button><ul style="display:none;" class="dropdown-link__container"><!--[--><li class="dropdown-link__item"><a href="/docs/Apai-MyRecord/My-2023/My2307" class="link" aria-label="2023-花开万里"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->2023-花开万里<!--]--></span></span><!--[--><!--]--></a></li><li class="dropdown-link__item"><a href="/docs/Apai-MyRecord/My-2024/My2401" class="link" aria-label="2024-随心而来"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->2024-随心而来<!--]--></span></span><!--[--><!--]--></a></li><!--]--></ul></div></div><div class="navbar-links__item"><a href="/docs/Apai-AboutMe/Lu-aboutMe" class="link" aria-label="关于我"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->关于我<!--]--></span></span><!--[--><!--]--></a></div><!--]--></nav><span class="xicon-container btn-toggle-dark-mode btn--dark-mode"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 32 32" style="width:20px;height:20px;font-size:20px;color:inherit;"><path d="M15 2h2v3h-2z" fill="currentColor"></path><path d="M27 15h3v2h-3z" fill="currentColor"></path><path d="M15 27h2v3h-2z" fill="currentColor"></path><path d="M2 15h3v2H2z" fill="currentColor"></path><path d="M5.45 6.884l1.414-1.415l2.121 2.122l-1.414 1.414z" fill="currentColor"></path><path d="M23 7.58l2.121-2.12l1.414 1.414l-2.121 2.121z" fill="currentColor"></path><path d="M23.002 24.416l1.415-1.414l2.12 2.122l-1.413 1.414z" fill="currentColor"></path><path d="M5.47 25.13L7.59 23L9 24.42l-2.12 2.12l-1.41-1.41z" fill="currentColor"></path><path d="M16 8a8 8 0 1 0 8 8a8 8 0 0 0-8-8zm0 14a6 6 0 0 1 0-12z" fill="currentColor"></path></svg></span><span class="xicon-container btn-toggle-menus"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 32 32" style="width:20px;height:20px;font-size:20px;color:inherit;"><circle cx="16" cy="8" r="2" fill="currentColor"></circle><circle cx="16" cy="16" r="2" fill="currentColor"></circle><circle cx="16" cy="24" r="2" fill="currentColor"></circle></svg></span></div><!--]--></header><div class="mobile-menus-container"><nav class="navbar-links mobile"><!--[--><div class="navbar-links__item"><a href="/" class="link router-link-active" aria-label="Home"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->Home<!--]--></span></span><!--[--><!--]--></a></div><div class="navbar-links__item"><a href="/categories/Java/1/" class="link" aria-label="分类组"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->分类组<!--]--></span></span><!--[--><!--]--></a></div><div class="navbar-links__item"><a href="/tags/Rests/1/" class="link" aria-label="标签组"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->标签组<!--]--></span></span><!--[--><!--]--></a></div><div class="navbar-links__item"><div class="dropdown-link"><button class="dropdown-link__title" type="button" aria-label="文档组"><span class="xicon-container left title"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->文档组<!--]--></span></span><span class="arrow down"></span></button><button class="dropdown-link--mobile__title" type="button" aria-label="文档组"><span class="title"><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->文档组<!--]--></span></span></span><span class="right arrow"></span></button><ul style="display:none;" class="dropdown-link__container"><!--[--><li class="dropdown-link__item"><a href="/docs/Web-develop/Html-Js" class="link" aria-label="Web-开发"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->Web-开发<!--]--></span></span><!--[--><!--]--></a></li><li class="dropdown-link__item"><a href="/docs/Java-develop/JavaMyUtil" class="link" aria-label="Java-开发"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->Java-开发<!--]--></span></span><!--[--><!--]--></a></li><li class="dropdown-link__item"><a href="/docs/Linux-develop/Linux" class="link" aria-label="Linux-系统"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->Linux-系统<!--]--></span></span><!--[--><!--]--></a></li><li class="dropdown-link__item"><a href="/docs/Rests-docs/Vuepress" class="link" aria-label="Apai-其他"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->Apai-其他<!--]--></span></span><!--[--><!--]--></a></li><!--]--></ul></div></div><div class="navbar-links__item"><div class="dropdown-link"><button class="dropdown-link__title" type="button" aria-label="花圃里"><span class="xicon-container left title"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->花圃里<!--]--></span></span><span class="arrow down"></span></button><button class="dropdown-link--mobile__title" type="button" aria-label="花圃里"><span class="title"><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->花圃里<!--]--></span></span></span><span class="right arrow"></span></button><ul style="display:none;" class="dropdown-link__container"><!--[--><li class="dropdown-link__item"><a href="/docs/Apai-MyRecord/My-2023/My2307" class="link" aria-label="2023-花开万里"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->2023-花开万里<!--]--></span></span><!--[--><!--]--></a></li><li class="dropdown-link__item"><a href="/docs/Apai-MyRecord/My-2024/My2401" class="link" aria-label="2024-随心而来"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->2024-随心而来<!--]--></span></span><!--[--><!--]--></a></li><!--]--></ul></div></div><div class="navbar-links__item"><a href="/docs/Apai-AboutMe/Lu-aboutMe" class="link" aria-label="关于我"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->关于我<!--]--></span></span><!--[--><!--]--></a></div><!--]--></nav><div class="appearance"><span>Appearance</span><span class="xicon-container btn-toggle-dark-mode"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 32 32" style="width:20px;height:20px;font-size:20px;color:inherit;"><path d="M15 2h2v3h-2z" fill="currentColor"></path><path d="M27 15h3v2h-3z" fill="currentColor"></path><path d="M15 27h2v3h-2z" fill="currentColor"></path><path d="M2 15h3v2H2z" fill="currentColor"></path><path d="M5.45 6.884l1.414-1.415l2.121 2.122l-1.414 1.414z" fill="currentColor"></path><path d="M23 7.58l2.121-2.12l1.414 1.414l-2.121 2.121z" fill="currentColor"></path><path d="M23.002 24.416l1.415-1.414l2.12 2.122l-1.413 1.414z" fill="currentColor"></path><path d="M5.47 25.13L7.59 23L9 24.42l-2.12 2.12l-1.41-1.41z" fill="currentColor"></path><path d="M16 8a8 8 0 1 0 8 8a8 8 0 0 0-8-8zm0 14a6 6 0 0 1 0-12z" fill="currentColor"></path></svg></span></div></div><div class="series-mask"></div><aside class="series-container"><div class="site-brand"><img class="logo" src="/logo.png" alt="阿派 | Apai Blog"><a href="/" class="site-name can-hide">阿派 | Apai Blog</a></div><!--[--><!--[--><section class="series-group series-item"><h5 class="series-heading">Java 笔记</h5><ul><li><!--[--><a href="/docs/Java-develop/JavaMyUtil.html" class="link series-item" aria-label="阿派的工具类"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->阿派的工具类<!--]--></span></span><!--[--><!--]--></a><!--]--></li><li><!--[--><a href="/docs/Java-develop/Java-basics.html" class="link series-item" aria-label="Java 基础"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->Java 基础<!--]--></span></span><!--[--><!--]--></a><!--]--></li><li><!--[--><a href="/docs/Java-develop/JavaJinJie02.html" class="link series-item" aria-label="Java 基础_进阶二"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->Java 基础_进阶二<!--]--></span></span><!--[--><!--]--></a><!--]--></li><li><!--[--><a href="/docs/Java-develop/JavaGongNeng03.html" class="link series-item" aria-label="Java 功能实现"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->Java 功能实现<!--]--></span></span><!--[--><!--]--></a><!--]--></li><li><!--[--><a href="/docs/Java-develop/JavaBiKeng04.html" class="link series-item" aria-label="Java 避坑及技巧"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->Java 避坑及技巧<!--]--></span></span><!--[--><!--]--></a><!--]--></li></ul></section><!--]--><!--[--><section class="series-group series-item"><h5 class="series-heading">Java 基础</h5><ul><li><!--[--><a href="/docs/Java-develop/JavaAPI.html" class="link series-item" aria-label="Java API"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->Java API<!--]--></span></span><!--[--><!--]--></a><!--]--></li><li><!--[--><a href="/docs/Java-develop/WebSocket.html" class="link series-item" aria-label="WebSocket"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->WebSocket<!--]--></span></span><!--[--><!--]--></a><!--]--></li><li><!--[--><a href="/docs/Java-develop/ShiWuAffair.html" class="link series-item" aria-label="Spring Boot 事务"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->Spring Boot 事务<!--]--></span></span><!--[--><!--]--></a><!--]--></li></ul></section><!--]--><!--[--><section class="series-group series-item"><h5 class="series-heading">MySql 数据库</h5><ul><li><!--[--><a href="/docs/Java-develop/MySql.html" class="link series-item" aria-label="MySql 数据库"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->MySql 数据库<!--]--></span></span><!--[--><!--]--></a><!--]--></li><li><!--[--><a href="/docs/Java-develop/MySqlFunction.html" class="link series-item" aria-label="MySql 函数"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->MySql 函数<!--]--></span></span><!--[--><!--]--></a><!--]--></li></ul></section><!--]--><!--[--><section class="series-group series-item"><h5 class="series-heading">Java 框架</h5><ul><li><!--[--><a href="/docs/Java-develop/Spring.html" class="link series-item" aria-label="Spring_框架"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->Spring_框架<!--]--></span></span><!--[--><!--]--></a><!--]--></li><li><!--[--><a href="/docs/Java-develop/SpringPeiZhi.html" class="link series-item" aria-label="Spring 配置详解"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->Spring 配置详解<!--]--></span></span><!--[--><!--]--></a><!--]--></li><li><!--[--><a href="/docs/Java-develop/MyBatisPlus.html" class="link series-item" aria-label="MyBatisPlus_框架"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->MyBatisPlus_框架<!--]--></span></span><!--[--><!--]--></a><!--]--></li><li><!--[--><a href="/docs/Java-develop/SpringSecurity.html" class="link series-item" aria-label="SpringSecurity 安全框架"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->SpringSecurity 安全框架<!--]--></span></span><!--[--><!--]--></a><!--]--></li></ul></section><!--]--><!--[--><section class="series-group series-item"><h5 class="series-heading active">微服务</h5><ul><li><!--[--><a href="/docs/Java-develop/SpringConfig.html" class="link series-item" aria-label="SpringConfig 微服务"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->SpringConfig 微服务<!--]--></span></span><!--[--><!--]--></a><!--]--></li><li><!--[--><a aria-current="page" href="/docs/Java-develop/Redis.html" class="router-link-active router-link-exact-active link router-link-active series-item active" aria-label="Redis 内存数据库"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->Redis 内存数据库<!--]--></span></span><!--[--><!--]--></a><!--]--></li><li><!--[--><a href="/docs/Java-develop/RabbitMQ.html" class="link series-item" aria-label="RabbitMQ 消息队列"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->RabbitMQ 消息队列<!--]--></span></span><!--[--><!--]--></a><!--]--></li></ul></section><!--]--><!--]--></aside><!--[--><main class="page-container"><h1 class="page-title">Redis 内存数据库</h1><div class="page-info"><span class="xicon-container left"><!--[--><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 32 32" class="xicon-icon" style="width:18px;height:18px;font-size:18px;color:inherit;"><path d="M16 4a5 5 0 1 1-5 5a5 5 0 0 1 5-5m0-2a7 7 0 1 0 7 7a7 7 0 0 0-7-7z" fill="currentColor"></path><path d="M26 30h-2v-5a5 5 0 0 0-5-5h-6a5 5 0 0 0-5 5v5H6v-5a7 7 0 0 1 7-7h6a7 7 0 0 1 7 7z" fill="currentColor"></path></svg><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->LuisApai<!--]--></span></span><span class="xicon-container left"><!--[--><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 32 32" class="xicon-icon" style="width:18px;height:18px;font-size:18px;color:inherit;"><path d="M26 4h-4V2h-2v2h-8V2h-2v2H6c-1.1 0-2 .9-2 2v20c0 1.1.9 2 2 2h20c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 22H6V12h20v14zm0-16H6V6h4v2h2V6h8v2h2V6h4v4z" fill="currentColor"></path></svg><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->2023/04/26<!--]--></span></span><!----><!----><!----></div><div class="theme-reco-default-content"><div><h2 id="redis-内存数据库" tabindex="-1"><a class="header-anchor" href="#redis-内存数据库" aria-hidden="true">#</a> redis 内存数据库</h2><p>参考: https://blog.csdn.net/guorui_java/article/details/129292178</p><h3 id="查看默认安装目录" tabindex="-1"><a class="header-anchor" href="#查看默认安装目录" aria-hidden="true">#</a> 查看默认安装目录</h3><p>源码包安装的软件。一般都在usr/local/bin下。redis采用源码包安装，进入usr/local/bin下</p><ul><li><p>redis-benchmark:性能测试工具，可以在自己本子运行，看看自己本子性能如何，服务启动起来后执行</p></li><li><p>redis-check-aof：修复有问题的AOF文件，rdb和aof后面讲</p></li><li><p>redis-check-dump：修复有问题的dump.rdb文件</p></li><li><p>redis-cli：客户端，操作入口</p></li><li><p>redis-sentinel：redis哨兵启动脚本</p></li><li><p>redis-server：Redis服务器启动命令</p></li></ul><h3 id="redis-安装配置方法" tabindex="-1"><a class="header-anchor" href="#redis-安装配置方法" aria-hidden="true">#</a> redis -- 安装配置方法</h3><h4 id="redis-安装" tabindex="-1"><a class="header-anchor" href="#redis-安装" aria-hidden="true">#</a> redis -- 安装</h4><p>1.解压 -- redis-5.0.4.tar.gz</p><ul><li>tar -zxvf redis-5.0.4.tar.gz</li></ul><p>2.编译 进入解压包</p><ul><li>yum -y install gcc-c++</li><li>注意：有可能第一次没装成功，那么就需要清一下缓存</li><li>make distclean 清缓存</li></ul><p>3.检查，通过</p><ul><li>make &amp;&amp; make install</li></ul><blockquote><ul><li>编译</li></ul><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>make
在源码包的根目录下执行make命令即可
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div></div></div><ul><li>安装</li></ul><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>make installls
在源码包的根目录下执行make install命令即可
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div></div></div></blockquote><h4 id="redis-配置" tabindex="-1"><a class="header-anchor" href="#redis-配置" aria-hidden="true">#</a> redis 配置</h4><p>将redis安装包下的redis.conf配置文件复制一份到/usr/local/bin目录下</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>[root@localhost redis-5.0.4]## cp redis.conf /usr/local/bin/
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>修改配置文件</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>daemonize yes

bind 192.168.174.128
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote><p>daemonize是用来指定redis是否要用守护线程的方式启动，当我们采用<strong>yes</strong>时，redis会在后台运行(说白了就是后台启动)，此时redis将一直运行，除非手动kill该进程，而采用<strong>no</strong>时，当前界面将进入redis的命令行界面，exit强制退出或者关闭连接工具(putty,xshell等)都会导致redis进程退出</p></blockquote><p>启动redis服务器</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code> cd /usr/local/bin
 ./redis-server redis.conf
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div></div></div><p><strong>启动redis客户端</strong></p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>redis-cli -h 192.168.174.128 -p 6379
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><blockquote><p>如果是redis服务器就在本机，那么ip地址就可以省略，如果不是本机就要带上redis服务器的ip地址，而且redis服务器的配置文件添加 bind 0.0.0.0 或者是bind 远程服务器的ip，如bind 192.168.128.128</p></blockquote><h2 id="redis-常用指令" tabindex="-1"><a class="header-anchor" href="#redis-常用指令" aria-hidden="true">#</a> redis 常用指令</h2><h3 id="redis-服务器关闭" tabindex="-1"><a class="header-anchor" href="#redis-服务器关闭" aria-hidden="true">#</a> redis 服务器关闭</h3><p>进入redis客户端后，执行shutdown</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379&gt; shutdown   #关闭redis服务器
127.0.0.1:6379&gt; exit       #退出客户端
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div></div></div><p>杀掉redis服务器进程</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>[root@localhost bin]## ps -ef|grep redis
[root@localhost bin]## kill -9 进程id
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="redis-数据库" tabindex="-1"><a class="header-anchor" href="#redis-数据库" aria-hidden="true">#</a> Redis 数据库</h3><p>redis默认16个数据库，类似数组下表从零开始，默认数据库为0，可以使用SELECT命令在连接上指定数据库id</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379&gt; select 0   #选择某个数据库
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>查看当前数据库中key-value键值对的数量</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379&gt;dbsize
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>查看当前数据库的key的数量</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379&gt;dbsize
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>清空当前数据库的所有k-v</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379&gt;flushdb
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>清空所有数据库的k-v</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379&gt;flushall
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><h3 id="redis单线程模型" tabindex="-1"><a class="header-anchor" href="#redis单线程模型" aria-hidden="true">#</a> redis单线程模型</h3><blockquote><p>redis是单线程来处理网络请求的，这里的单线程，只是在处理我们的网络请求的时候只有一个线程来处理，即一个线程处理所有网络请求，一个正式的Redis Server运行的时候肯定是不止一个线程的，例如Redis进行持久化的时候会以子进程或者子线程的方式执行</p><p>1、单线程模型流程</p><p>Redis客户端对服务端的每次调用都经历了发送命令，执行命令，返回结果三个过程。其中执行命令阶段，由于Redis是单线程来处理命令的，所有每一条到达服务端的命令不会立刻执行，所有的命令都会进入一个队列中，然后逐个被执行。并且多个客户端发送的命令的执行顺序是不确定的。但是可以确定的是不会有两条命令被同时执行，不会产生并发问题，这就是Redis的单线程基本模型</p><p>2、单线程模型好处</p><p>采用单线程,避免了不必要的上下文切换和竞争条件，redis采用非阻塞IO - IO多路复用， epoll做为I/O多路复用技术的实现，这里“多路”指的是和多个网络客户端连接，“复用”指的是复用同一个线程。采用多路 I/O 复用技术可以让单个线程高效的处理多个连接请求（尽量减少网络 IO 的时间消耗）</p></blockquote><h2 id="redis数据类型指令" tabindex="-1"><a class="header-anchor" href="#redis数据类型指令" aria-hidden="true">#</a> Redis数据类型指令</h2><blockquote><p><strong>Redis的五大数据类型：</strong></p><p><strong>Redis字符串（String） 、Redis列表（List）、Redis集合（Set）、Redis哈希（Hash）、Redis有序集合Zset（sorted set）</strong></p></blockquote><h3 id="string-字符串" tabindex="-1"><a class="header-anchor" href="#string-字符串" aria-hidden="true">#</a> string（字符串）</h3><p>String（字符串）string是redis最基本的类型，你可以理解成与Memcached一模一样的类型，一个key对应一个value。string类型是二进制安全的。意思是redis的string可以包含任何数据。比如jpg图片或者序列化的对象 。string类型是Redis最基本的数据类型，一个redis中字符串value最多可以是512M</p><h5 id="set-key-value" tabindex="-1"><a class="header-anchor" href="#set-key-value" aria-hidden="true">#</a> set key value</h5><p>语法： set key value [EX seconds] [PX milliseconds] [NX|XX] 将字符串值 value 关联到 key 如果 key 已经持有其他值， set就覆写旧值，无视类型。 对于某个原本带有生存时间（TTL）的键来说， 当 set命令成功在这个键上执行时， 这个键原有的 TTL 将被清除</p><p>可选参数 从 Redis 2.6.12 版本开始， set 命令的行为可以通过一系列参数来修改：</p><ul><li>EX second：设置键的过期时间为 second 秒。 SET key value EX second 效果等同于 SETEX key second value。</li><li>PX millisecond：设置键的过期时间为 millisecond毫秒。 SET key value PX millisecond 效果等同于 PSETEX key millisecond value</li><li>NX ：只在键不存在时，才对键进行设置操作。 SET key value NX 效果等同于 SETNX key value</li><li>XX ：只在键已经存在时，才对键进行设置操作</li></ul><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>redis 127.0.0.1:6379&gt; SET key &quot;value&quot;
redis 127.0.0.1:6379&gt; SET key-with-expire-time &quot;hello&quot; EX 10
redis 127.0.0.1:6379&gt; SET key-with-pexpire-time &quot;moto&quot; PX 2000
redis 127.0.0.1:6379&gt; SET not-exists-key &quot;value&quot; NX    #键不存在时，设置成功
redis 127.0.0.1:6379&gt; SET exists-key &quot;value&quot; XX        #键存在时，设置成功
redis 127.0.0.1:6379&gt; SET key-with-expire-and-NX &quot;hello&quot; EX 10 NX
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h5 id="get-key" tabindex="-1"><a class="header-anchor" href="#get-key" aria-hidden="true">#</a> get key</h5><p>返回 key 所关联的字符串值 如果 key 不存在那么返回特殊值 nil 假如 key 储存的值不是字符串类型，返回一个错误，因为 GET 只能用于处理字符串值。</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>redis&gt; GET db
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><h5 id="del-key" tabindex="-1"><a class="header-anchor" href="#del-key" aria-hidden="true">#</a> del key</h5><p>删除某个key</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>redis&gt; del username
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><h5 id="append-key-value" tabindex="-1"><a class="header-anchor" href="#append-key-value" aria-hidden="true">#</a> append key value</h5><p>如果 key 已经存在并且是一个字符串， APPEND 命令将 value 追加到 key 原来的值的末尾。 如果 key 不存在， APPEND 就简单地将给定 key 设为 value ，就像执行 SET key value 一样</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>redis&gt; EXISTS myphone               ## myphone 不存在
(integer) 0
redis&gt; APPEND myphone &quot;nokia&quot; 
redis&gt; APPEND myphone &quot; - 1110&quot;
redis&gt; GET myphone
&quot;nokia - 1110&quot;
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h5 id="strlen-key" tabindex="-1"><a class="header-anchor" href="#strlen-key" aria-hidden="true">#</a> strlen key</h5><p>返回 key 所储存的字符串值的长度。 当 key 储存的不是字符串值时，返回一个错误。</p><p>返回值： 字符串值的长度。 当 key 不存在时，返回 0</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379[1]&gt; strlen username
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><h5 id="incr-key" tabindex="-1"><a class="header-anchor" href="#incr-key" aria-hidden="true">#</a> INCR key</h5><p>将 key 中储存的数字值增一。 如果 key 不存在，那么 key 的值会先被初始化为 0 ，然后再执行 INCR 操作。 如果值包含错误的类型，或字符串类型的值不能表示为数字，那么返回一个错误</p><p>返回值：执行 INCR 命令之后 key 的值。</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379[1]&gt; set k1 2
127.0.0.1:6379[1]&gt; incr k1
127.0.0.1:6379[1]&gt; decr k1   #将 key 中储存的数字值减一
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h5 id="incrby-key" tabindex="-1"><a class="header-anchor" href="#incrby-key" aria-hidden="true">#</a> INCRBY key</h5><p>将 key 所储存的值加上增量 increment 。 如果 key 不存在，那么 key 的值会先被初始化为 0 ，然后再执行 INCRBY 命令。 如果值包含错误的类型，或字符串类型的值不能表示为数字，那么返回一个错误。本操作的值限制在 64 位(bit)有符号数字表示之内。</p><p>返回值：加上 increment 之后， key 的值</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379[1]&gt; incrby k1 3
127.0.0.1:6379[1]&gt; decrby k1 2    #将 key 所储存的值减量 increment 
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div></div></div><h5 id="getrange-key-start-end" tabindex="-1"><a class="header-anchor" href="#getrange-key-start-end" aria-hidden="true">#</a> GETRANGE key start end</h5><p>返回 key 中字符串值的子字符串，字符串的截取范围由 start 和 end 两个偏移量决定(包括 start 和 end 在内)。 负数偏移量表示从字符串最后开始计数， -1 表示最后一个字符， -2 表示倒数第二个，以此类推。 GETRANGE 通过保证子字符串的值域(range)不超过实际字符串的值域来处理超出范围的值域请求。</p><p>返回值： 截取得出的子字符串。</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379[1]&gt; set username zhangsanfeng
127.0.0.1:6379[1]&gt; getrange username 0 -1
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div></div></div><h5 id="setrange-key-offset-value" tabindex="-1"><a class="header-anchor" href="#setrange-key-offset-value" aria-hidden="true">#</a> SETRANGE key offset value</h5><p>用 value 参数覆写(overwrite)给定 key 所储存的字符串值，从偏移量 offset 开始。不存在的 key 当作空白字符串处理</p><p>返回值： 被 SETRANGE 修改之后，字符串的长度</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379&gt; set name zhangsanfeng
127.0.0.1:6379&gt; SETRANGE name 4 xxx
127.0.0.1:6379&gt; get name
&quot;zhanxxxnfeng&quot;
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h5 id="setex-key-seconds-value" tabindex="-1"><a class="header-anchor" href="#setex-key-seconds-value" aria-hidden="true">#</a> SETEX key seconds value</h5><p>将值 value 关联到 key ，并将 key 的生存时间设为 seconds (以秒为单位)。 如果 key 已经存在， SETEX 命令将覆写旧值。</p><p>这个命令类似于以下两个命令：</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>SET key value
EXPIRE key seconds  ## 设置生存时间
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div></div></div><p>返回值： 设置成功时返回 OK 。 当 seconds 参数不合法时，返回一个错误。</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>redis&gt; SETEX cache_user_id 60 10086   #设置60秒
OK
redis&gt; GET cache_user_id  ## 值
&quot;10086&quot;
redis&gt; TTL cache_user_id  ## 剩余生存时间
(integer) 49
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h5 id="setnx-key-value" tabindex="-1"><a class="header-anchor" href="#setnx-key-value" aria-hidden="true">#</a> SETNX key value</h5><p>将 key 的值设为 value ，当且仅当 key 不存在。 若给定的 key 已经存在，则 SETNX 不做任何动作。</p><p>SETNX 是『SET if Not exists』(如果不存在，则 SET)的简写。 返回值： 设置成功，返回 1 。 设置失败，返回 0 。</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>redis&gt; EXISTS job                ## job 不存在
(integer) 0

redis&gt; SETNX job &quot;programmer&quot;    ## job 设置成功
(integer) 1
redis&gt; GET job 
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h5 id="mset-key-value-key-value" tabindex="-1"><a class="header-anchor" href="#mset-key-value-key-value" aria-hidden="true">#</a> MSET key value [key value ...]</h5><p>同时设置一个或多个 key-value 对。 (m:more) 如果某个给定 key 已经存在，那么 MSET 会用新值覆盖原来的旧值，如果这不是你所希望的效果，请考虑使用 MSETNX 命令：它只会在所有给定 key 都不存在的情况下进行设置操作。</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379[1]&gt; mset k1 v1 k2 v2 k3 v3
127.0.0.1:6379[1]&gt; mget k1 k2 k3
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div></div></div><h5 id="mget-key-key" tabindex="-1"><a class="header-anchor" href="#mget-key-key" aria-hidden="true">#</a> MGET key [key ...]</h5><p>返回所有(一个或多个)给定 key 的值。 如果给定的 key 里面，有某个 key 不存在，那么这个 key 返回特殊值 nil 。因此，该命令永不失败</p><p>返回值： 一个包含所有给定 key 的值的列表</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>redis&gt; SET redis redis.com
redis&gt; SET mongodb mongodb.org
redis&gt; MGET redis mongodb mysql
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h5 id="msetnx-key-value-key-value" tabindex="-1"><a class="header-anchor" href="#msetnx-key-value-key-value" aria-hidden="true">#</a> MSETNX key value [key value ...]</h5><p>同时设置一个或多个 key-value 对，当且仅当所有给定 key 都不存在。 即使只有一个给定 key 已存在， MSETNX 也会拒绝执行所有给定 key 的设置操作。 MSETNX 是原子性的，因此它可以用作设置多个不同 key 表示不同字段(field)的唯一性逻辑对象(unique logic object)，所有字段要么全被设置，要么全不被设置</p><p>返回值： 当所有 key 都成功设置，返回 1 。 如果所有给定 key 都设置失败(至少有一个 key 已经存在)，那么返回 0 。</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>## 对不存在的 key 进行 MSETNX
redis&gt; MSETNX rmdbs &quot;MySQL&quot; nosql &quot;MongoDB&quot; key-value-store &quot;redis&quot;
(integer) 1
redis&gt; MGET rmdbs nosql key-value-store
1) &quot;MySQL&quot;
2) &quot;MongoDB&quot;
3) &quot;redis&quot;

## MSET 的给定 key 当中有已存在的 key
redis&gt; MSETNX rmdbs &quot;Sqlite&quot; language &quot;python&quot;  ## rmdbs 键已经存在，操作失败
(integer) 0
redis&gt; EXISTS language                          ## 因为 MSET 是原子性操作，language 没有被设置
(integer) 0
redis&gt; GET rmdbs                                ## rmdbs 也没有被修改
&quot;MySQL&quot;
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="hash-哈希" tabindex="-1"><a class="header-anchor" href="#hash-哈希" aria-hidden="true">#</a> Hash（哈希）</h3><p>Hash（哈希）Redis hash 是一个键值对集合。Redis hash是一个string类型的field和value的映射表，hash特别适合用于存储对象。类似Java里面的Map&lt;String,Object&gt;，在hash类型中，也是一个键值对，key不变 v又是一个键值对</p><h5 id="hset-key-field-value" tabindex="-1"><a class="header-anchor" href="#hset-key-field-value" aria-hidden="true">#</a> HSET key field value</h5><p>将哈希表 key 中的域 field 的值设为 value 。 如果 key 不存在，一个新的哈希表被创建并进行 HSET 操作。如果域 field 已经存在于哈希表中，旧值将被覆盖</p><p>返回值： 如果 field 是哈希表中的一个新建域，并且值设置成功，返回 1 。 如果哈希表中域 field 已经存在且旧值已被新值覆盖，返回 0 。</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379&gt; hset user id 1     user是key   value 是 id 1    value是一个键值对
127.0.0.1:6379&gt; hget user id  
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div></div></div><p>sinter求交集：sinter key1 key2 key3 .....</p><p>sunion求并集 sunion key1 key2 key3 .....</p><p>sdiff 求差 sdiff key1 key2 .....</p><h5 id="hget-key-field" tabindex="-1"><a class="header-anchor" href="#hget-key-field" aria-hidden="true">#</a> HGET key field</h5><p>返回哈希表 key 中给定域 field 的值</p><p>返回值： 给定域的值，当给定域不存在或是给定 key 不存在时，返回 nil</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379&gt; hget user id  
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><h5 id="hmset-key-field-value-field-value" tabindex="-1"><a class="header-anchor" href="#hmset-key-field-value-field-value" aria-hidden="true">#</a> HMSET key field value [field value ...]</h5><p>同时将多个 field-value (域-值)对设置到哈希表 key 中。 此命令会覆盖哈希表中已存在的域。如果 key 不存在，一个空哈希表被创建并执行 HMSET 操作</p><p>返回值： 如果命令执行成功，返回 OK 。 当 key 不是哈希表(hash)类型时，返回一个错误</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379&gt; hmset user id 1 name zhangsan
OK
127.0.0.1:6379&gt; HMGET user id name
1) &quot;1&quot;
2) &quot;zhangsan&quot;
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h5 id="hmget-key-field-field" tabindex="-1"><a class="header-anchor" href="#hmget-key-field-field" aria-hidden="true">#</a> HMGET key field [field ...]</h5><p>HMGET key field [field ...] 返回哈希表 key 中，一个或多个给定域的值。</p><p>如果给定的域不存在于哈希表，那么返回一个 nil 值。因为不存在的 key 被当作一个空哈希表来处理，所以对一个不存在的 key 进行 HMGET 操作将返回一个只带有 nil 值的表。</p><p>返回值： 一个包含多个给定域的关联值的表，表值的排列顺序和给定域参数的请求顺序一样</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379&gt; hmset user id 1 name zhangsan
127.0.0.1:6379&gt; HMGET user id name
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div></div></div><h5 id="hgetall-key" tabindex="-1"><a class="header-anchor" href="#hgetall-key" aria-hidden="true">#</a> HGETALL key</h5><p>返回哈希表 key 中，所有的域和值。 在返回值里，紧跟每个域名(field name)之后是域的值(value)，所以返回值的长度是哈希表大小的两倍。</p><p>返回值： 以列表形式返回哈希表的域和域的值。若 key 不存在，返回空列表</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379&gt; HGETALL user
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><h5 id="hdel-key-field-field" tabindex="-1"><a class="header-anchor" href="#hdel-key-field-field" aria-hidden="true">#</a> HDEL key field [field ...]</h5><p>删除哈希表 key 中的一个或多个指定域，不存在的域将被忽略</p><p>返回值: 被成功移除的域的数量，不包括被忽略的域</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379&gt; HDEL user id name
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><h5 id="hlen-key" tabindex="-1"><a class="header-anchor" href="#hlen-key" aria-hidden="true">#</a> HLEN key</h5><p>返回哈希表 key 中域的数量</p><p>返回值： 哈希表中域的数量。当 key 不存在时，返回 0</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379&gt; HLEN user
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><h5 id="hexists-key-field" tabindex="-1"><a class="header-anchor" href="#hexists-key-field" aria-hidden="true">#</a> HEXISTS key field</h5><p>查看哈希表 key 中，给定域 field 是否存在</p><p>返回值： 如果哈希表含有给定域，返回 1 。 如果哈希表不含有给定域，或 key 不存在，返回 0</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379&gt; HEXISTS user name        判断key是user 的值中 是否含有name的键
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><h5 id="hkeys-key" tabindex="-1"><a class="header-anchor" href="#hkeys-key" aria-hidden="true">#</a> HKEYS key</h5><p>返回哈希表 key 中的所有域。</p><p>返回值： 一个包含哈希表中所有域的表。 当 key 不存在时，返回一个空表</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379&gt; HKEYS user
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><h5 id="hvals-key" tabindex="-1"><a class="header-anchor" href="#hvals-key" aria-hidden="true">#</a> HVALS key</h5><p>返回哈希表 key 中所有域的值。</p><p>返回值： 一个包含哈希表中所有值的表。当 key 不存在时，返回一个空表</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379&gt; HVALS user
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><h5 id="hincrby-key-field-increment" tabindex="-1"><a class="header-anchor" href="#hincrby-key-field-increment" aria-hidden="true">#</a> HINCRBY key field increment</h5><p>为哈希表 key 中的域 field 的值加上增量 increment,增量也可以为负数，相当于对给定域进行减法操作</p><p>如果 key 不存在，一个新的哈希表被创建并执行 HINCRBY 命令。 如果域 field 不存在，那么在执行命令前，域的值被初始化为 0</p><p>返回值： 执行 HINCRBY 命令之后，哈希表 key 中域 field 的值</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379&gt; HSET user age 2
(integer) 1
127.0.0.1:6379&gt; HINCRBY user age 5
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h5 id="hincrbyfloat-key-field-increment" tabindex="-1"><a class="header-anchor" href="#hincrbyfloat-key-field-increment" aria-hidden="true">#</a> HINCRBYFLOAT key field increment</h5><p>为哈希表 key 中的域 field 加上浮点数增量 increment</p><p>如果哈希表中没有域 field ，那么 HINCRBYFLOAT 会先将域 field 的值设为 0 ，然后再执行加法操作。如果键 key 不存在，那么 HINCRBYFLOAT 会先创建一个哈希表，再创建域 field ，最后再执行加法操作</p><p>当以下任意一个条件发生时，返回一个错误： 域 field 的值不是字符串类型(因为 redis 中的数字和浮点数都以字符串的形式保存，所以它们都属于字符串类型） 域 field 当前的值或给定的增量 increment 不能解释(parse)为双精度浮点数(double precision floating point number)</p><p>返回值： 执行加法操作之后 field 域的值</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379&gt; HINCRBYFLOAT user age 0.5
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><h3 id="list-列表" tabindex="-1"><a class="header-anchor" href="#list-列表" aria-hidden="true">#</a> list（列表）</h3><p>List（列表）Redis 列表是简单的字符串列表，按照插入顺序排序。你可以添加一个元素导列表的头部（左边）或者尾部（右边）。它的底层实际是个链表</p><h5 id="lpush-key-value-value" tabindex="-1"><a class="header-anchor" href="#lpush-key-value-value" aria-hidden="true">#</a> LPUSH key value [value ...]</h5><p>将一个或多个值 value 插入到列表 key 的表头</p><p>如果有多个 value 值，那么各个 value 值按从左到右的顺序依次插入到表头： 比如说，对空列表 mylist 执行命令 LPUSH mylist a b c ，列表的值将是 c b a ，这等同于原子性地执行 LPUSH mylist a 、 LPUSH mylist b 和 LPUSH mylist c 三个命令。 如果 key 不存在，一个空列表会被创建并执行 LPUSH 操作</p><p>返回值： 执行 LPUSH 命令后，列表的长度</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379&gt; lpush list01 0 1 2 3 4 5
127.0.0.1:6379&gt; LRANGE list01 0 -1
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div></div></div><h5 id="rpush-key-value-value" tabindex="-1"><a class="header-anchor" href="#rpush-key-value-value" aria-hidden="true">#</a> RPUSH key value [value ...]</h5><p>将一个或多个值 value 插入到列表 key 的表尾(最右边)。</p><p>如果有多个 value 值，那么各个 value 值按从左到右的顺序依次插入到表尾：比如对一个空列表 mylist 执行 RPUSH mylist a b c ，得出的结果列表为 a b c ，等同于执行命令 RPUSH mylist a 、 RPUSH mylist b 、 RPUSH mylist c 。 如果 key 不存在，一个空列表会被创建并执行 RPUSH 操作。当 key 存在但不是列表类型时，返回一个错误。</p><p>返回值： 执行 RPUSH 操作后，表的长度。</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379&gt; rpush list01 0 1 2 3 4 5
127.0.0.1:6379&gt; LRANGE list01 0 -1
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div></div></div><h5 id="lrange-key-start-stop" tabindex="-1"><a class="header-anchor" href="#lrange-key-start-stop" aria-hidden="true">#</a> LRANGE key start stop</h5><p>返回列表 key 中指定区间内的元素，区间以偏移量 start 和 stop 指定。下标(index)参数 start 和 stop 都以 0 为底，也就是说，以 0 表示列表的第一个元素，以 1 表示列表的第二个元素，以此类推。你也可以使用负数下标，以 -1 表示列表的最后一个元素， -2 表示列表的倒数第二个元素，以此类推</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379&gt; rpush list01 0 1 2 3 4 5
127.0.0.1:6379&gt; LRANGE list01 0 -1
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div></div></div><h5 id="llen-key" tabindex="-1"><a class="header-anchor" href="#llen-key" aria-hidden="true">#</a> LLen key</h5><p>返回列表 key 的长度。</p><p>如果 key 不存在，则 key 被解释为一个空列表，返回 0 . 如果 key 不是列表类型，返回一个错误。</p><p>返回值： 列表 key 的长度。</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>redis&gt; LPUSH job &quot;cook food&quot;
(integer) 1

redis&gt; LPUSH job &quot;have lunch&quot;
(integer) 2

redis&gt; LLEN job
(integer) 2
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h5 id="lpop-key" tabindex="-1"><a class="header-anchor" href="#lpop-key" aria-hidden="true">#</a> LPOP key</h5><p>移除并返回列表 key 的头元素。</p><p>返回值： 列表的头元素。 当 key 不存在时，返回 nil 。</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379&gt; lpush list01 0 1 2 3 4 5
127.0.0.1:6379&gt; LPOP list01
&quot;5&quot;
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h5 id="rpop-key" tabindex="-1"><a class="header-anchor" href="#rpop-key" aria-hidden="true">#</a> RPOP key</h5><p>移除并返回列表 key 的尾元素</p><p>返回值： 列表的尾元素。 当 key 不存在时，返回 nil</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379&gt; rpush list02 0 1 2 3 4 5
(integer) 6
127.0.0.1:6379&gt; RPOP list02
&quot;5&quot;
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h5 id="lindex-key-index" tabindex="-1"><a class="header-anchor" href="#lindex-key-index" aria-hidden="true">#</a> LINDEX key index</h5><p>返回列表 key 中，下标为 index 的元素</p><p>下标(index)参数 start 和 stop 都以 0 为底，也就是说，以 0 表示列表的第一个元素，以 1 表示列表的第二个元素，以此类推。你也可以使用负数下标，以 -1 表示列表的最后一个元素， -2 表示列表的倒数第二个元素，以此类推。如果 key 不是列表类型，返回一个错误</p><p>返回值: 列表中下标为 index 的元素。 如果 index 参数的值不在列表的区间范围内(out of range)，返回 nil</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379&gt; lindex list01  3   #返回集合里面的第四个元素
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><h5 id="lrem-key-count-value" tabindex="-1"><a class="header-anchor" href="#lrem-key-count-value" aria-hidden="true">#</a> LREM key count value</h5><p>根据参数 count 的值，移除列表中与参数 value 相等的元素。</p><p>count 的值可以是以下几种：</p><p>count &gt; 0 : 从表头开始向表尾搜索，移除与 value 相等的元素，数量为 count 。 count &lt; 0 : 从表尾开始向表头搜索，移除与 value 相等的元素，数量为 count 的绝对值。 count = 0 : 移除表中所有与 value 相等的值</p><p>返回值： 被移除元素的数量。 因为不存在的 key 被视作空表(empty list)，所以当 key 不存在时， LREM 命令总是返回 0</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379&gt; lpush list01 0 1 2 3 3 3 3
127.0.0.1:6379&gt; lrem  list01 2 3    #删除集合里面2个3
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div></div></div><h5 id="ltrim-key-start-stop" tabindex="-1"><a class="header-anchor" href="#ltrim-key-start-stop" aria-hidden="true">#</a> LTRIM key start stop</h5><p>对一个列表进行修剪(trim)，就是说，让列表只保留指定区间内的元素，不在指定区间之内的元素都将被删除。举个例子，执行命令 LTRIM list 0 2 ，表示只保留列表 list 的前三个元素，其余元素全部删除。下标(index)参数 start 和 stop 都以 0 为底，也就是说，以 0 表示列表的第一个元素，以 1 表示列表的第二个元素，以此类推。</p><p>你也可以使用负数下标，以 -1 表示列表的最后一个元素， -2 表示列表的倒数第二个元素，以此类推。当 key 不是列表类型时，返回一个错误。LTRIM 命令通常和 LPUSH 命令或 RPUSH 命令配合使用</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>redis&gt; LRANGE alpha 0 -1       ## alpha 是一个包含 5 个字符串的列表
1) &quot;h&quot;
2) &quot;e&quot;
3) &quot;l&quot;
4) &quot;l&quot;
5) &quot;o&quot;

redis&gt; LTRIM alpha 1 -1        ## 删除 alpha 列表索引为 0 的元素
OK
redis&gt; LRANGE alpha 0 -1       ## &quot;h&quot; 被删除了
1) &quot;e&quot;
2) &quot;l&quot;
3) &quot;l&quot;
4) &quot;o&quot;
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h5 id="rpoplpush-source-destination" tabindex="-1"><a class="header-anchor" href="#rpoplpush-source-destination" aria-hidden="true">#</a> RPOPLPUSH source destination</h5><p>将列表 source 中的最后一个元素(尾元素)弹出，并返回给客户端。将 source 弹出的元素插入到列表 destination ，作为 destination 列表的的头元素。</p><p>返回值 被弹出的元素</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379&gt; lrange list02 0 -1
1) &quot;6&quot;
2) &quot;5&quot;
3) &quot;4&quot;
127.0.0.1:6379&gt; LRANGE list01 0 -1
(empty list or set)
127.0.0.1:6379&gt; RPOPLPUSH list02 list01
&quot;4&quot;
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h5 id="lset-key-index-value" tabindex="-1"><a class="header-anchor" href="#lset-key-index-value" aria-hidden="true">#</a> LSET key index value</h5><p>将列表 key 下标为 index 的元素的值设置为 value 。 下标是从0开始的 当 index 参数超出范围，或对一个空列表( key 不存在)进行 LSET 时，返回一个错误</p><p>返回值： 操作成功返回 ok ，否则返回错误信息。</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379&gt; LRANGE list02 0 -1
1) &quot;6&quot;
2) &quot;5&quot;
127.0.0.1:6379&gt; LSET list02 1 x     #下标1的元素是5  用x 替换
127.0.0.1:6379&gt; LRANGE list02 0 -1
1) &quot;6&quot;
2) &quot;x&quot;
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h5 id="linsert-key-before-after-pivot-value" tabindex="-1"><a class="header-anchor" href="#linsert-key-before-after-pivot-value" aria-hidden="true">#</a> LINSERT key BEFORE|AFTER pivot value</h5><p>将值 value 插入到列表 key 当中，位于值 pivot 之前或之后。当 pivot 不存在于列表 key 时，不执行任何操作。当 key 不存在时， key 被视为空列表，不执行任何操作。如果 key 不是列表类型，返回一个错误。</p><p>返回值: 如果命令执行成功，返回插入操作完成之后，列表的长度。 如果没有找到 pivot ，返回 -1 。 如果 key 不存在或为空列表，返回 0 。</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379&gt; LPUSH list01 1 2 3 4 5
127.0.0.1:6379&gt; LINSERT list01 before 2 xxx  #在元素2的前面插入xxx
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="set-集合" tabindex="-1"><a class="header-anchor" href="#set-集合" aria-hidden="true">#</a> Set（集合）</h3><p>Set（集合）Redis的Set是string类型的无序集合。它是通过HashTable实现实现的</p><h5 id="_6-4-1-sadd-key-member-member" tabindex="-1"><a class="header-anchor" href="#_6-4-1-sadd-key-member-member" aria-hidden="true">#</a> 6.4.1 SADD key member [member ...]</h5><p>将一个或多个 member 元素加入到集合 key 当中，已经存在于集合的 member 元素将被忽略。假如 key 不存在，则创建一个只包含 member 元素作成员的集合。当 key 不是集合类型时，返回一个错误。</p><p>返回值: 被添加到集合中的新元素的数量，不包括被忽略的元素</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379&gt; SADD set01 1 1 2 2 3 4
127.0.0.1:6379&gt; SMEMBERS set01  
1 2 3 4
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h5 id="_6-4-1-smembers-key" tabindex="-1"><a class="header-anchor" href="#_6-4-1-smembers-key" aria-hidden="true">#</a> 6.4.1 SMEMBERS key</h5><p>返回集合 key 中的所有成员。不存在的 key 被视为空集合。 返回值: 集合中的所有成员</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379&gt; SMEMBERS set01 
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><h5 id="_6-4-2-sismember-key-member" tabindex="-1"><a class="header-anchor" href="#_6-4-2-sismember-key-member" aria-hidden="true">#</a> 6.4.2 SISMEMBER key member</h5><p>判断 member 元素是否集合 key 的成员</p><p>返回值: 如果 member 元素是集合的成员，返回 1 。 如果 member 元素不是集合的成员，或 key 不存在，返回 0 。</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379&gt; sismember set01 2   ## 判断集合里面是否有某个元素  
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><h5 id="_6-4-3-srandmember-key-count" tabindex="-1"><a class="header-anchor" href="#_6-4-3-srandmember-key-count" aria-hidden="true">#</a> 6.4.3 SRANDMEMBER key [count]</h5><p>如果命令执行时，只提供了 key 参数，那么返回集合中的一个随机元素。从 Redis 2.6 版本开始， SRANDMEMBER 命令接受可选的 count 参数</p><p>如果 count 为正数，且小于集合基数，那么命令返回一个包含 count 个元素的数组，数组中的元素各不相同。如果 count 大于等于集合基数，那么返回整个集合。 如果 count 为负数，那么命令返回一个数组，数组中的元素可能会重复出现多次，而数组的长度为 count 的绝对值。</p><p>返回值: 只提供 key 参数时，返回一个元素；如果集合为空，返回 nil 。 如果提供了 count 参数，那么返回一个数组；如果集合为空，返回空数组</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379&gt; SADD set02  1 2 3 4 5 6 7 8 9 
(integer) 9
127.0.0.1:6379&gt; SRANDMEMBER set02 3
1) &quot;7&quot;
2) &quot;3&quot;
3) &quot;2&quot;
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h5 id="_6-4-4-spop-key" tabindex="-1"><a class="header-anchor" href="#_6-4-4-spop-key" aria-hidden="true">#</a> 6.4.4 SPOP key</h5><p>移除并返回集合中的一个随机元素。如果只想获取一个随机元素，但不想该元素从集合中被移除的话，可以使用 SRANDMEMBER 命令。</p><p>返回值: 被移除的随机元素。 当 key 不存在或 key 是空集时，返回 nil 。</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379&gt; SPOP set02   #随机删除集合中的一个元素
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><h5 id="_6-4-5-scard-key" tabindex="-1"><a class="header-anchor" href="#_6-4-5-scard-key" aria-hidden="true">#</a> 6.4.5 SCARD key</h5><p>返回集合 key 的基数(集合中元素的数量)</p><p>返回值： 集合的基数。 当 key 不存在时，返回 0</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>redis&gt; SADD set01 pc printer phone
(integer) 3
redis&gt; SCARD set01   ## 非空集合
(integer) 3
redis&gt; DEL set01
(integer) 1
redis&gt; SCARD set01   ## 空集合
(integer) 0
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h5 id="_6-4-6-smove-source-destination-member" tabindex="-1"><a class="header-anchor" href="#_6-4-6-smove-source-destination-member" aria-hidden="true">#</a> 6.4.6 SMOVE source destination member</h5><p>将 member 元素从 source 集合移动到 destination 集合。SMOVE 是原子性操作。</p><p>如果 source 集合不存在或不包含指定的 member 元素，则 SMOVE 命令不执行任何操作，仅返回 0 。否则， member 元素从 source 集合中被移除，并添加到 destination 集合中去。当 destination 集合已经包含 member 元素时， SMOVE 命令只是简单地将 source 集合中的 member 元素删除。当 source 或 destination 不是集合类型时，返回一个错误。</p><p>返回值: 如果 member 元素被成功移除，返回 1 。 如果 member 元素不是 source 集合的成员，并且没有任何操作对 destination 集合执行，那么返回 0</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>redis&gt; SMOVE set02 set01 9  把集合set02中的元素9移动到set01集合中
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><h5 id="_6-4-7-srem-key-member-member" tabindex="-1"><a class="header-anchor" href="#_6-4-7-srem-key-member-member" aria-hidden="true">#</a> 6.4.7 SREM key member [member ...]</h5><p>移除集合 key 中的一个或多个 member 元素，不存在的 member 元素会被忽略。 当 key 不是集合类型，返回一个错误。</p><p>返回值: 被成功移除的元素的数量，不包括被忽略的元素</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379&gt; sadd set01 &quot;c&quot; &quot;lisp&quot; &quot;python&quot; &quot;ruby&quot;
(integer) 4
127.0.0.1:6379&gt;  SREM set01 ruby
(integer) 1
127.0.0.1:6379&gt; SMEMBERS set01
1) &quot;c&quot;
2) &quot;python&quot;
3) &quot;lisp&quot;
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="zset-有序集合" tabindex="-1"><a class="header-anchor" href="#zset-有序集合" aria-hidden="true">#</a> zset(有序集合)</h3><p>zset(sorted set：有序集合) Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。zset的成员是唯一的,但分数(score)却可以重复。</p><h5 id="zadd-key-score-member-score-member" tabindex="-1"><a class="header-anchor" href="#zadd-key-score-member-score-member" aria-hidden="true">#</a> ZADD key score member [ [score member] ...]</h5><p>将一个或多个 member 元素及其 score 值加入到有序集 key 当中。 如果某个 member 已经是有序集的成员，那么更新这个 member 的 score 值，并通过重新插入这个 member 元素，来保证该 membe在正确的位置上。score 值可以是整数值或双精度浮点数。</p><p>如果 key 不存在，则创建一个空的有序集并执行 ZADD 操作。当 key 存在但不是有序集类型时，返回一个错误。</p><p>返回值: 被成功添加的新成员的数量，不包括那些被更新的、已经存在的成员</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379&gt; ZADD set03 60 v1 70 v2 80 v3
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><h5 id="zcard-key" tabindex="-1"><a class="header-anchor" href="#zcard-key" aria-hidden="true">#</a> ZCARD key</h5><p>返回有序集 key 的基数</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379&gt; ZCARD set03
(integer) 3
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div></div></div><h5 id="zrange-key-start-stop-withscores" tabindex="-1"><a class="header-anchor" href="#zrange-key-start-stop-withscores" aria-hidden="true">#</a> ZRANGE key start stop [WITHSCORES]</h5><p>返回有序集 key 中，指定区间内的成员。其中成员的位置按 score 值递增(从小到大)来排序。具有相同 score 值的成员按字典序(lexicographical order )来排列。如果你需要成员按 score 值递减(从大到小)来排列，请使用 ZREVRANGE 命令</p><p>下标参数 start 和 stop 都以 0 为底，也就是说，以 0 表示有序集第一个成员，以 1 表示有序集第二个成员，以此类推。你也可以使用负数下标，以 -1 表示最后一个成员， -2 表示倒数第二个成员，以此类推</p><p>返回值: 指定区间内，带有 score 值(可选)的有序集成员的列表</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379&gt; ZRANGE set03 0 -1 
1) &quot;v1&quot;
2) &quot;v2&quot;
3) &quot;v3&quot;
127.0.0.1:6379&gt; ZRANGE set03 0 -1  withscores
1) &quot;v1&quot;
2) &quot;60&quot;
3) &quot;v2&quot;
4) &quot;70&quot;
5) &quot;v3&quot;
6) &quot;80&quot;
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h5 id="_6-5-4-zrem-key-member-member" tabindex="-1"><a class="header-anchor" href="#_6-5-4-zrem-key-member-member" aria-hidden="true">#</a> 6.5.4 ZREM key member [member ...]</h5><p>移除有序集 key 中的一个或多个成员，不存在的成员将被忽略。当 key 存在但不是有序集类型时，返回一个错误。 返回值: 被成功移除的成员的数量，不包括被忽略的成员。</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379&gt; ZREM set03 v3
(integer) 1
127.0.0.1:6379&gt; ZRANGE set03 0 -1  withscores
1) &quot;v1&quot;
2) &quot;60&quot;
3) &quot;v2&quot;
4) &quot;70&quot;
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h5 id="zscore-key-member" tabindex="-1"><a class="header-anchor" href="#zscore-key-member" aria-hidden="true">#</a> ZSCORE key member</h5><p>返回有序集 key 中，成员 member 的 score 值。如果 member 元素不是有序集 key 的成员，或 key 不存在，返回 nil 。</p><p>返回值: member 成员的 score 值，以字符串形式表示</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379&gt; ZSCORE set03 v2
&quot;70&quot;
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div></div></div><h5 id="zcount-key-min-max" tabindex="-1"><a class="header-anchor" href="#zcount-key-min-max" aria-hidden="true">#</a> ZCOUNT key min max</h5><p>返回有序集 key 中， score 值在 min 和 max 之间(默认包括 score 值等于 min 或 max )的成员的数量</p><p>返回值: score 值在 min 和 max 之间的成员的数量。</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379&gt; ZCOUNT set03 60 70
(integer) 2
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div></div></div><h5 id="zrevrange-key-start-stop-withscores" tabindex="-1"><a class="header-anchor" href="#zrevrange-key-start-stop-withscores" aria-hidden="true">#</a> ZREVRANGE key start stop [WITHSCORES]</h5><p>返回有序集 key 中，指定区间内的成员。其中成员的位置按 score 值递减(从大到小)来排列。具有相同 score 值的成员按字典序的逆序(reverse lexicographical order)排列。除了成员按 score 值递减的次序排列这一点外， ZREVRANGE 命令的其他方面和 ZRANGE 命令一样。</p><p>返回值: 指定区间内，带有 score 值(可选)的有序集成员的列表。</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379&gt; ZREVRANGE set03 0 -1
1) &quot;v2&quot;
2) &quot;v1&quot;
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h5 id="zrevrangebyscore-key-max-min-withscores" tabindex="-1"><a class="header-anchor" href="#zrevrangebyscore-key-max-min-withscores" aria-hidden="true">#</a> ZREVRANGEBYSCORE key max min [WITHSCORES]</h5><p>返回有序集 key 中， score 值介于 max 和 min 之间(默认包括等于 max 或 min )的所有的成员。有序集成员按 score 值递减(从大到小)的次序排列。</p><p>返回值: 指定区间内，带有 score值(可选)的有序集成员的列表</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>redis &gt; ZADD salary 10086 jack
(integer) 1
redis &gt; ZADD salary 5000 tom
(integer) 1
redis &gt; ZADD salary 7500 peter
(integer) 1
redis &gt; ZADD salary 3500 joe
(integer) 1
redis &gt; ZREVRANGEBYSCORE salary 10000 2000  ## 逆序排列薪水介于 10000 和 2000 之间的成员
1) &quot;peter&quot;
2) &quot;tom&quot;
3) &quot;joe&quot;
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h2 id="redis配置文件-参数" tabindex="-1"><a class="header-anchor" href="#redis配置文件-参数" aria-hidden="true">#</a> redis配置文件-参数</h2><h4 id="_7-1-常规" tabindex="-1"><a class="header-anchor" href="#_7-1-常规" aria-hidden="true">#</a> 7.1 常规</h4><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>daemonize no
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>Redis默认是不作为守护进程来运行的。你可以把这个设置为&quot;yes&quot;让它作为守护进程来运行。默认是no 注意，当作为守护进程的时候，Redis会把进程ID写到 /var/run/redis.pid</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>pidfile /var/run/redis.pid
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>当以守护进程方式运行的时候，Redis会把进程ID默认写到 /var/run/redis.pid。你可以在这里修改路径。</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>port 6379
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>接受连接的特定端口，默认是6379。 如果端口设置为0，Redis就不会监听TCP套接字。</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>bind 127.0.0.1
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>如果你想的话，你可以绑定某个具体服务器的ip，如：bind 192.168.128.128，此时远程客户端连接 redis-cli -h 192.168.128.128 -p 6379，当然也可以设置成 bind 0.0.0.0</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>timeout 0
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>一个客户端空闲多少秒后关闭连接。(0代表禁用，永不关闭)，默认为0</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>loglevel verbose
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>设置服务器调试等级。 其它值如下：</p><blockquote><p>debug （很多信息，对开发/测试有用）</p><p>verbose （很多精简的有用信息，但是不像debug等级那么多）</p><p>notice （适量的信息，基本上是你生产环境中需要的程度）</p><p>warning （只有很重要/严重的信息会记录下来）</p></blockquote><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>logfile stdout
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>指明日志文件名。也可以使用&quot;stdout&quot;来强制让Redis把日志信息写到标准输出上。 注意：如果Redis以守护进程方式运行，而你设置日志显示到标准输出的话，那么日志会发送到 /dev/null</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>syslog-enabled no
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>要使用系统日志记录器很简单，只要设置 &quot;syslog-enabled&quot; 为 &quot;yes&quot; 就可以了。默认为no</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>databases 16
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>设置数据库个数。默认数据库是 DB 0，你可以通过SELECT dbid WHERE dbid（0～&#39;databases&#39; - 1）来为每个连接使用不同的数据库</p><h4 id="_7-2-快照" tabindex="-1"><a class="header-anchor" href="#_7-2-快照" aria-hidden="true">#</a> 7.2 快照</h4><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>save 900 1     ## 900秒（15分钟）之后，且至少1次变更
save 300 10    #300秒（5分钟）之后，且至少10次变更
save 60 10000  #60秒之后，且至少10000次变更
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>把数据库存到磁盘上， 会在指定秒数和数据变化次数之后把数据库写到磁盘上，你要想不写磁盘的话就把所有 &quot;save&quot; 设置注释掉就行了注意：当设置redis持久化后，符合save规则后立马生成dump.rdb文件，dump.rdb文件不是一开始就生成的</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>rdbcompression yes
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>导出到dump .rdb 数据库时是否用LZF压缩字符串对象，默认设置为 &quot;yes&quot;，所以几乎总是生效的，如果希望RDB进程节省一点CPU时间，设置为no，但是可能最后的dump.rdb文件会很大</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>dbfilename dump.rdb
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>rdb持久化的数据库文件名，默认是 dump.rdb</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>dir ./      
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>工作目录，数据库会写到这个目录下，文件名就是上面的 &quot;dbfilename&quot; 的值， 累加文件也放这里，注意你这里指定的必须是目录，不是文件名，默认是当前目录</p><h4 id="_7-3-同步" tabindex="-1"><a class="header-anchor" href="#_7-3-同步" aria-hidden="true">#</a> 7.3 同步</h4><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>slaveof &lt;masterip&gt; &lt;masterport&gt;  redis3.2以上   replicaof &lt;masterip&gt; &lt;masterport&gt;
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>主从同步。通过 slaveof 配置来实现Redis实例的备份。 注意，这里是本地从远端复制数据。也就是说，本地可以有不同的数据库文件、绑定不同的IP、监听不同的端口。</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>masterauth &lt;master-password&gt;     #默认为空
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>如果master设置了密码（通过下面的 &quot;requirepass&quot; 选项来配置），那么slave在开始同步之前必须进行身份验证，否则它的同步请求会被拒绝</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>replica-serve-stale-data yes    #默认为yes
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>当一个slave去和master的连接，或者同步正在进行中，slave的行为有两种可能</p><ol><li>如果 replica-serve-stale-data 设置为 &quot;yes&quot; (默认值)，slave会继续响应客户端请求，可能是正常数据，也可能是还没获得值的空数</li><li>如果 replica-serve-stale-data 设置为 &quot;no&quot;，slave会回复&quot;正在从master同步（SYNC with master in progress）&quot;来处理客户端请求，</li></ol><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>replica-read-only yes
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>从机是否只能读，不能有写指令，默认值为yes</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>repl-ping-replica-period 10
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>slave根据指定的时间间隔向服务器发送ping请求，时间间隔可以通过 repl_ping_slave_period 来设置，默认10秒来定义心跳（PING）间隔</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>repl-timeout 60
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>这个参数一定不能小于repl-ping-replica-period，可以考虑为repl-ping-replica-period的3倍或更大。定义多长时间内均PING不通时，判定心跳超时。对于redis集群，达到这个值并不会发生主从切换,主从何时切换由参数cluster-node-timeout控制，只有master状态为fail后，它的slaves才能发起选举，默认60秒</p><h4 id="_7-4-安全" tabindex="-1"><a class="header-anchor" href="#_7-4-安全" aria-hidden="true">#</a> 7.4 安全</h4><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>requirepass foobared
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>要求客户端在处理任何命令时都要验证身份和密码， 这在你信不过来访者时很有用，为了向后兼容的话，这段应该注释掉。而且大多数人不需要身份验证（例如：它们运行在自己的服务器上。）</p><p>警告：因为Redis太快了，所以居心不良的人可以每秒尝试150k的密码来试图破解密码。这意味着你需要一个高强度的密码，否则破解太容易了，可以把这个注释去掉</p><p>客户端在登陆redis时，是需要密码进行验证的</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379&gt; ping
(error) NOAUTH Authentication required.
127.0.0.1:6379&gt; AUTH foobared
OK
127.0.0.1:6379&gt; ping
PONG
//通过命令来设置密码
127.0.0.1:6379&gt; CONFIG GET requirepass
1) &quot;requirepass&quot;
2) &quot;foobared&quot;
127.0.0.1:6379&gt; CONFIG set requirepass 1234
OK
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>rename-command CONFIG &quot;&quot;
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>命令重命名，在共享环境下，可以为危险命令改变名字。比如，你可以为 CONFIG 改个其他不太容易猜到的名字，这样你自己仍然可以使用，而别人却没法做坏事了，例如：rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52</p><h4 id="_7-5-限制" tabindex="-1"><a class="header-anchor" href="#_7-5-限制" aria-hidden="true">#</a> 7.5 限制</h4><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>maxclients 128
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>设置最多同时连接客户端数量，默认没有限制，这个关系到Redis进程能够打开的文件描述符数量，特殊值&quot;0&quot;表示没有限制，一旦达到这个限制，Redis会关闭所有新连接并发送错误&quot;达到最大用户数上限（max number of clients reached）</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>maxmemory &lt;bytes&gt;     #如 maxmemory 100mb
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>用于控制redis可使用的最大内存容量。如果超过maxmemory的值，就会动用淘汰策略来处理expire字典中的键，默认为0,表示&quot;无限制&quot;,最终由OS物理内存大小决定(如果物理内存不足,有可能会使用swap)</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>maxmemory-policy volatile-lru
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>内存策略：如果达到内存限制了，Redis如何删除key。对所有策略来说，如果Redis找不到合适的可以删除的key都会在写操作时返回一个错误，你可以在下面五个策略里面选：</p><ul><li>volatile-lru -&gt; 对&quot;过期集合&quot;中的数据采取LRU(近期最少使用Least Recently Used)算法.如果对key使用&quot;expire&quot;指令指定了过期时间,那么此key将会被添加到&quot;过期集合&quot;中。将已经过期/LRU的数据优先移除.如果&quot;过期集合&quot;中全部移除仍不能满足内存需求,将OOM.</li><li>allkeys-lru -&gt; 对所有的数据,采用LRU算法，不管是否过期</li><li>volatile-random -&gt; 对&quot;过期集合&quot;中的数据采取&quot;随即选取&quot;算法,并移除选中的K-V,直到&quot;内存足够&quot;为止. 如果如果&quot;过期集合&quot;中全部移除全部移除仍不能满足,将OOM</li><li>allkeys-&gt;random -&gt; 对所有的数据,采取&quot;随机选取&quot;算法,并移除选中的K-V,直到&quot;内存足够&quot;为止</li><li>volatile-ttl -&gt; 对&quot;过期集合&quot;中的数据采取TTL算法(最小存活时间),移除即将过期的数据</li><li>noeviction -&gt; 不做任何干扰操作,直接返回OOM异常</li></ul><blockquote><p>经验：</p><ul><li>在所有的 key 都是最近最经常使用，那么就需要选择 allkeys-lru 进行置换最近最不经常使用的 key，如果你不确定使用哪种策略，那么推荐使用 allkeys-lru</li><li>如果所有的 key 的访问概率都是差不多的，那么可以选用 allkeys-random 策略去置换数据</li><li>如果对数据有足够的了解，能够为 key 指定 hint（通过expire/ttl指定），那么可以选择 volatile-ttl 进行置换</li></ul></blockquote><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>maxmemory-samples 10
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>设置样本个数，maxmemory-samples在redis-3.0.0中的默认配置为5，如果增加，会提高LRU或TTL的精准度，redis作者测试的结果是当这个配置为10时已经非常接近全量LRU的精准度了，并且增加maxmemory-samples会导致在主动清理时消耗更多的CPU时间</p><h4 id="_7-6-纯累加模式" tabindex="-1"><a class="header-anchor" href="#_7-6-纯累加模式" aria-hidden="true">#</a> 7.6 纯累加模式</h4><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>appendonly no    #默认值
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>默认情况下，Redis是异步的把数据导出到磁盘上。这种情况下，当Redis挂掉的时候，最新的数据就丢了。 如果不希望丢掉任何一条数据的话就该用纯累加模式：一旦开启这个模式，Redis会把每次写入的数据在接收后都写入 appendonly.aof 文件，每次启动时Redis都会把这个文件的数据读入内存里。</p><p>注意，异步导出的数据库文件和纯累加文件可以并存，如果纯累加模式开启了，那么Redis会在启动时载入日志文件而忽略导出的 dump.rdb 文件</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>appendfilename appendonly.aof
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>纯累加文件名字（默认：&quot;appendonly.aof&quot;）</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>appendfsync always
appendfsync everysec
appendfsync no
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>每隔多久调用操作系统fsync() 操作，马上把数据写到磁盘上，不要再等了，默认值为everysec，有些操作系统会真的把数据马上刷到磁盘上；有些则要磨蹭一下，但是会尽快去做，Redis支持三种不同的模式：</p><ul><li>no：不要立刻刷，只有在操作系统需要刷的时候再刷。比较快。</li><li>always：每次写操作都立刻写入到aof文件。慢，但是最安全。</li><li>everysec：每秒写一次，折衷方案，默认的 &quot;everysec&quot; 通常来说能在速度和数据安全性之间取得比较好的平衡。</li></ul><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>no-appendfsync-on-rewrite no
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>bgrewriteaof机制，在一个子进程中进行aof的重写，从而不阻塞主进程对其余命令的处理，重写主要解决了aof文件过大问题</p><p>现在问题出现了，同时在执行bgrewriteaof操作（重写是要去操作appendonly.aof文件的）和主进程写aof文件的操作（主进程每隔疫一秒就会把写指令追加到appendonly.aof中，也是要去操作这个文件），两者都会操作磁盘，而bgrewriteaof往往会涉及大量磁盘操作，这样就会造成主进程在写aof文件的时候出现阻塞的情形，现在no-appendfsync-on-rewrite参数出场了。如果该参数设置为no，是最安全的方式，不会丢失数据，但是要忍受阻塞的问题。如果设置为yes呢，只是写入了缓冲区，因此这样并不会造成阻塞（因为没有竞争磁盘），但是如果这个时候redis挂掉，就会丢失数据。丢失多少数据呢？在linux的操作系统的默认设置下，最多会丢失30s的数据。</p><p>因此，如果应用系统无法忍受延迟，而可以容忍少量的数据丢失，则设置为yes。如果应用系统无法忍受数据丢失，则设置为no</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div></div></div><p>当AOF文件随着写命令的运行膨胀时，当文件大小触碰到临界时，rewrite会被运行，rewrite会像replication一样，fork出一个子进程，创建一个临时文件，遍历数据库，将每个key、value对输出到临时文件。输出格式就是Redis的命令，但是为了减小文件大小，会将多个key、value键值对集合起来用一条命令表达。在rewrite期间的写操作会保存在内存的rewrite buffer中，rewrite成功后这些操作也会复制到临时文件中，在最后临时文件会代替AOF文件</p><p>auto-aof-rewrite-percentage 100：当前AOF文件大小是上次日志重写得到AOF文件大小的二倍时，自动启动新的日志重写过程 auto_aofrewrite_min_size: 当前aof文件大于多少字节后才触发。避免在aof较小的时候无谓行为。默认大小为64mb</p><h4 id="_7-7-慢查询日志" tabindex="-1"><a class="header-anchor" href="#_7-7-慢查询日志" aria-hidden="true">#</a> 7.7 慢查询日志</h4><p>Redis Slow Log是一个用于记录超过指定执行时间的查询的系统。执行时间不包括与客户端交谈，发送答复等I / O操作，而仅包括实际执行命令所需的时间（这是命令执行的唯一阶段，在该阶段线程被阻塞并且不能同时满足其他要求）。</p><p>通俗的讲使用这个命令可以读取或重置 Redis 慢速查询日志。<strong>就是 redis 可以把执行时间超过我们设定值的命令记录下来，slowlog 是记录到内存中的，所以查询非常快</strong>。这里的执行时间不包括 I/O 操作,比如与客户端,发送应答等,就是实际执行命令所需的时间</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>slowlog-log-slower-than 10000
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>slowlog-log-slower-than 设置超时时间，单位是微秒（1000000就是1秒），表示记录超过个时间的命令</p><p>请注意：负数将禁用慢速日志记录，而零值将强制记录每个命令</p><p>两种方式实现慢日志配置：</p><ol><li>可以通过配置 redis.conf 来完成。</li><li>运行时，使用 CONFIG GET 和 CONFIG SET 命令配置</li></ol><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379&gt; config set slowlog-log-slower-than 0    #设置为0
OK
127.0.0.1:6379&gt; config get slowlog-log-slower-than
1) &quot;slowlog-log-slower-than&quot;
2) &quot;0&quot;
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>要读取慢日志，请使用SLOWLOG GET命令</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379&gt; set k3 v3
OK
127.0.0.1:6379&gt; set k4 v4
OK
127.0.0.1:6379&gt; SLOWLOG get 
1) 1) (integer) 4             //slowlog 唯一标识
   2) (integer) 1632391958    //unix 时间戳
   3) (integer) 12           //命令执行的时间，单位：微秒
   4) 1) &quot;set&quot;				 //执行了什么命令
      2) &quot;k3&quot;
      3) &quot;v3&quot;
...................
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote><p>slowlog get #列出所有的慢查询日志 slowlog get 2 #只列出2条 slowlog len #查看慢查询日志条数</p></blockquote><p>那么问题来了，slowlog 是记录再内存中的，如果记录所有的命令 log 会不会把内存不够用呢？答案是当然不会。slowlog 记录的 命令数是有最大长度限制的，我们可以通过 slowlog-max-len 来查询 slowlog 的最大长度。最小值为零。当一个新的命令被记录下来，并且如果已经达到它的最大长度时，more是记录的命令达到128个之后，最旧的一个 log 将从队列中删除，FIFO</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>slowlog-max-len 128
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><h4 id="_7-8-包含" tabindex="-1"><a class="header-anchor" href="#_7-8-包含" aria-hidden="true">#</a> 7.8 包含</h4><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>include /path/to/local.conf
include /path/to/other.conf
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div></div></div><p>包含一个或多个其他配置文件。这在你有标准配置模板但是每个redis服务器又需要个性设置的时候很有用。包含文件特性允许你引人其他配置文件，所以好好利用吧。</p><h2 id="redis持久化" tabindex="-1"><a class="header-anchor" href="#redis持久化" aria-hidden="true">#</a> redis持久化</h2><p>由于 Redis 是一个内存数据库，所谓内存数据库，就是将数据库中的内容保存在内存中，这与传统的MySQL，Oracle等关系型数据库直接将内容保存到硬盘中相比，内存数据库的读写效率比传统数据库要快的多（内存的读写效率远远大于硬盘的读写效率）。但是保存在内存中也随之带来了一个缺点，一旦断电或者宕机，那么内存数据库中的数据将会全部丢失。</p><p>为了解决这个缺点，Redis提供了将内存数据持久化到硬盘，以及用持久化文件来恢复数据库数据的功能。Redis 支持两种形式的持久化，一种是RDB快照（snapshotting），另外一种是AOF（append-only-file）</p><h3 id="_8-1-rdb-redis-database" tabindex="-1"><a class="header-anchor" href="#_8-1-rdb-redis-database" aria-hidden="true">#</a> 8.1 RDB（Redis DataBase）</h3><h5 id="_1-rdb-简介" tabindex="-1"><a class="header-anchor" href="#_1-rdb-简介" aria-hidden="true">#</a> 1. RDB 简介</h5><p>RDB是Redis用来进行持久化的一种方式，是把当前内存中的数据集快照写入磁盘，也就是 Snapshot 快照（数据库中所有键值对数据）。恢复时是将快照文件直接读到内存里</p><h5 id="_2-触发方式" tabindex="-1"><a class="header-anchor" href="#_2-触发方式" aria-hidden="true">#</a> 2. 触发方式</h5><p>RDB 有两种触发方式，分别是自动触发和手动触发</p><h5 id="_1-自动触发" tabindex="-1"><a class="header-anchor" href="#_1-自动触发" aria-hidden="true">#</a> ① 自动触发</h5><p>在 redis.conf 配置文件中的 SNAPSHOTTING 下</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>save 900 1：表示900 秒内如果至少有 1 个 key 的值变化，则保存
save 300 10：表示300 秒内如果至少有 10 个 key 的值变化，则保存
save 60 10000：表示60 秒内如果至少有 10000 个 key 的值变化，则保存
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>当然如果你只是用Redis的缓存功能，不需要持久化，那么你可以注释掉所有的 save 行来停用保存功能。可以直接一个空字符串来实现停用：save &quot;&quot;</p><p>配置文件相关参数说明：</p><ul><li><p>stop-writes-on-bgsave-error：默认值是yes， 首先redis 会创建一个新的后台进程进行dump rdb，创建快照（硬盘上，产生一个新的rdb文件）需要 20s时间，redis主进程，在这20s内，会继续接受客户端命令，但是，就在这20s内，创建快照出错了，比如磁盘满了，那么redis就会拒绝 新的写入，也就是说，它认为，当前持久化数据出现了问题，你就不要再set，如果值为no，则可以set</p></li><li><p>rdbcompression yes：默认值是yes。对于存储到磁盘中的快照，可以设置是否进行压缩存储。如果是的话，redis会采用LZF算法进行压缩。如果你不想消耗CPU来进行压缩的话，可以设置为关闭此功能，但是存储在磁盘上的快照会比较大</p></li><li><p>rdbchecksum：默认值是yes。在存储快照后，我们还可以让redis使用CRC64算法来进行数据校验，但是这样做会增加大约10%的性能消耗，如果希望获取到最大的性能提升，可以关闭此功能。</p></li></ul><blockquote><p>注：fork的作用是复制一个与当前进程一样的进程。新进程的所有数据（变量、环境变量、程序计数器等）数值都和原进程一致，但是是一个全新的进程，并作为原进程的子进程，</p></blockquote><h5 id="_2-手动触发" tabindex="-1"><a class="header-anchor" href="#_2-手动触发" aria-hidden="true">#</a> ② 手动触发</h5><blockquote><p>shutdown 关闭 会自动执行保存</p></blockquote><p>手动触发Redis进行RDB持久化的命令有两种</p><p>1、save：该命令会阻塞当前Redis服务器，执行save命令期间，Redis不能处理其他命令，直到RDB过程完成为止，很显然该命令对于内存比较大的实例会造成长时间阻塞，这是致命的缺陷，为了解决此问题，Redis提供了第二种方式</p><p>2、bgsave：执行该命令时，Redis会在后台异步进行快照操作，持久化的同时主进程还可以响应客户端请求。具体操作是Redis进程执行fork操作创建子进程，RDB持久化过程由子进程负责，完成后自动结束。阻塞只发生在子进程，不会阻塞主进程，一般时间很短</p><blockquote><p>基本上 Redis 内部所有的RDB操作都是采用 bgsave 命令</p><p>当执行 flushall 命令，也会产生dump.rdb文件，但里面是空的</p><p>如果在规定的时间没有写符合条件的n个key，这个时候执行shutdown，也会保存，因为执行shutdown指令是会先把数据保存到本地的，shutdown 默认采取 shutdown save模式，也可以手动指定 shutdown nosave不保存。如果是意外退出不会，什么是意外退出呢？如杀掉redis服务器的进程，或者是ctrl+c直接宕掉redis服务器</p></blockquote><p>小实验：</p><p>1、设置：save 60 5 也就是说1分钟内要改变5个key，</p><p>2、删除dump.rdb, 然后在登陆redis客户端，在2分钟内修改10个key</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379&gt; set k1 v1 
127.0.0.1:6379&gt; set k2 v2 .......  set k5 v5
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div></div></div><p>当我们用20秒的时间就set 5个key-value键值对的话，那么这个dump.rdb文件就会马上生成（其实是执行了redis检测到规定时间内有了相应的修改key操作，就会调用bgsave指令执行持久化操作），不需要等到1分钟后才生成</p><h5 id="_3-恢复数据" tabindex="-1"><a class="header-anchor" href="#_3-恢复数据" aria-hidden="true">#</a> 3. 恢复数据</h5><p>将备份文件 (dump.rdb) 移动到 redis 安装目录并启动服务即可，redis就会自动加载文件数据至内存了。Redis 服务器在载入 RDB 文件期间，会一直处于阻塞状态，直到载入工作完成为止</p><h5 id="_4-停止-rdb-持久化" tabindex="-1"><a class="header-anchor" href="#_4-停止-rdb-持久化" aria-hidden="true">#</a> 4. 停止 RDB 持久化</h5><p>有些情况下，我们只想利用Redis的缓存功能，并不想使用 Redis 的持久化功能，那么这时候我们最好停掉 RDB 持久化。可以通过上面讲的在配置文件 redis.conf 中，可以注释掉所有的 save 行来停用保存功能或者直接一个空字符串来实现停用：save &quot;&quot;</p><p>也可以通过命令：</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>redis-cli config set save &quot; &quot;
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><h5 id="_5-rdb-的优势和劣势" tabindex="-1"><a class="header-anchor" href="#_5-rdb-的优势和劣势" aria-hidden="true">#</a> 5. RDB 的优势和劣势</h5><p>①、优势</p><p>1、RDB是一个非常紧凑(compact)的文件，它保存了redis 在某个时间点上的数据集。这种文件非常适合用于进行备份和灾难恢复。</p><p>2、生成RDB文件的时候，redis主进程会fork()一个子进程来处理所有保存工作，主进程不需要进行任何磁盘IO操作。</p><p>3、RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快</p><p>②、劣势</p><p>1、RDB方式数据没办法做到实时持久化/秒级持久化。因为bgsave每次运行都要执行fork操作创建子进程，属于重量级操作，如果不 采用压缩算法(内存中的数据被克隆了一份，大致2倍的膨胀性需要考虑)，频繁执行成本过高(影响性能)</p><p>2、在一定间隔时间做一次备份，所以如果redis意外down掉的话，就会丢失最后一次快照后的所有修改(数据有丢失)</p><h5 id="_6-rdb-自动保存的原理" tabindex="-1"><a class="header-anchor" href="#_6-rdb-自动保存的原理" aria-hidden="true">#</a> 6. RDB 自动保存的原理</h5><p>Redis有个服务器状态结构：</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>struct redisService{
     //1、记录保存save条件的数组
     struct saveparam *saveparams;
     //2、修改计数器
     long long dirty;
     //3、上一次执行保存的时间
     time_t lastsave;
}
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>①、首先看记录保存save条件的数组 saveparam，里面每个元素都是一个 saveparams 结构</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>struct saveparam{
     //秒数
     time_t seconds;
     //修改数
     int changes;
};
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>前面我们在 redis.conf 配置文件中进行了关于save 的配置</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>save 900 1：表示900 秒内如果至少有 1 个 key 的值变化，则保存
save 300 10：表示300 秒内如果至少有 10 个 key 的值变化，则保存
save 60 10000：表示60 秒内如果至少有 10000 个 key 的值变化，则保存
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>那么服务器状态中的saveparam 数组将会是如下的样子</p><p>②、dirty 计数器和lastsave 属性</p><p>dirty 计数器记录距离上一次成功执行 save 命令或者 bgsave 命令之后，Redis服务器进行了多少次修改（包括写入、删除、更新等操作）。</p><p>lastsave 属性是一个时间戳，记录上一次成功执行 save 命令或者 bgsave 命令的时间。</p><p>通过这两个命令，当服务器成功执行一次修改操作，那么dirty 计数器就会加 1，而lastsave 属性记录上一次执行save或bgsave的时间，Redis 服务器还有一个周期性操作函数 severCron ,默认每隔 100 毫秒就会执行一次，该函数会遍历并检查 saveparams 数组中的所有保存条件，只要有一个条件被满足，那么就会执行 bgsave 命令。</p><p>执行完成之后，dirty 计数器更新为 0 ，lastsave 也更新为执行命令的完成时间</p><p>AOF持久化</p><h5 id="_1-aof简介" tabindex="-1"><a class="header-anchor" href="#_1-aof简介" aria-hidden="true">#</a> 1.AOF简介</h5><p>Redis的持久化方式之一RDB是通过保存数据库中的键值对来记录数据库的状态。而另一种持久化方式 AOF 则是通过保存Redis服务器所执行的写命令来记录数据库状态。</p><p>比如对于如下命令</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379&gt; set k1 v1
OK
127.0.0.1:6379&gt; sadd set01 1 2 3 4
(integer) 4
127.0.0.1:6379&gt; LPUSH list01 1 1 1 2 3 4 5
(integer) 7
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>RDB 持久化方式就是将 str1,set01,list01 这三个键值对保存到 RDB文件中，而 AOF 持久化则是将执行的 set,sadd,lpush 三个命令保存到 AOF 文件中</p><h5 id="_2-aof配置" tabindex="-1"><a class="header-anchor" href="#_2-aof配置" aria-hidden="true">#</a> 2. AOF配置</h5><p>在 redis.conf 配置文件的 APPEND ONLY MODE 下：</p><p>① <strong>appendonly</strong>：默认值为no，redis 默认使用的是rdb方式持久化，如果要开启 AOF 持久化方式，需要将 appendonly 修改为 yes。</p><p>② <strong>appendfilename</strong> ：aof文件名，默认是&quot;appendonly.aof&quot;</p><p>③ **appendfsync：**aof持久化策略的配置；</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>no表示不执行fsync，由操作系统保证数据同步到磁盘，速度最快，但是不太安全；
always表示每次写入都执行fsync，以保证数据同步到磁盘，效率很低；
everysec表示每秒执行一次fsync，可能会导致丢失这1s数据。通常选择 everysec ，兼顾安全性和效率。
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>④ <strong>no-appendfsync-on-rewrite</strong>：在aof重写或者写入文件的时候，会执行大量IO，此时对于everysec和always的aof模式来说，执行fsync会造成阻塞过长时间，no-appendfsync-on-rewrite字段设置为默认设置为no。如果对延迟要求很高的应用，这个字段可以设置为yes，否则还是设置为no，这样对持久化特性来说这是更安全的选择。 设置为yes表示rewrite期间对新写操作不fsync,暂时存在内存中,等rewrite完成后再写入，默认为no，建议yes。Linux的默认fsync策略是30秒。可能丢失30秒数据。默认值为no。</p><p>⑤ <strong>auto-aof-rewrite-percentage</strong>：默认值为100。aof自动重写配置，当目前aof文件大小超过上一次重写的aof文件大小的百分之多少进行重写，即当aof文件增长到一定大小的时候，Redis能够调用bgrewriteaof对日志文件进行重写。当前AOF文件大小是上次日志重写得到AOF文件大小的二倍（设置为100）时，自动启动新的日志重写过程。</p><p>⑥ <strong>auto-aof-rewrite-min-size</strong>：64mb。设置允许重写的最小aof文件大小，避免了达到约定百分比但尺寸仍然很小的情况还要重写。</p><h5 id="_3-开启-aof" tabindex="-1"><a class="header-anchor" href="#_3-开启-aof" aria-hidden="true">#</a> 3. 开启 AOF</h5><p>将 redis.conf 的 appendonly 配置改为 yes 即可。可以通过 config get dir 命令获取保存的路径</p><h5 id="_4-aof-文件恢复" tabindex="-1"><a class="header-anchor" href="#_4-aof-文件恢复" aria-hidden="true">#</a> 4. AOF 文件恢复</h5><p>重启 Redis 之后就会进行 AOF 文件的载入。</p><p>异常修复命令：redis-check-aof --fix 文件名(appendonly.aof)</p><h5 id="_5-aof-重写" tabindex="-1"><a class="header-anchor" href="#_5-aof-重写" aria-hidden="true">#</a> 5. AOF 重写</h5><p>由于AOF持久化是Redis不断将写命令记录到 AOF 文件中，随着Redis不断的进行，AOF 的文件会越来越大，文件越大，占用服务器内存越大以及 AOF 恢复要求时间越长。为了解决这个问题，Redis新增了重写机制，当AOF文件的大小超过所设定的阈值时，Redis就会启动AOF文件的内容压缩，只保留可以恢复数据的最小指令集合。可以使用命令 bgrewriteaof 来重写</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379&gt; FLUSHALL
OK
127.0.0.1:6379&gt; sadd user &quot;cat&quot;
(integer) 1
127.0.0.1:6379&gt; sadd user &quot;dog&quot; &quot;panda&quot; &quot;tiger&quot;
(integer) 3
127.0.0.1:6379&gt; SREM user &quot;cat&quot;
(integer) 1
127.0.0.1:6379&gt; SADD user &quot;lion&quot; &quot;cat&quot;
(integer) 2
127.0.0.1:6379&gt; SDIFF user
1) &quot;lion&quot;
2) &quot;tiger&quot;
3) &quot;dog&quot;
4) &quot;panda&quot;
5) &quot;cat&quot;
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果不进行 AOF 文件重写，那么 AOF 文件将保存四条 SADD 命令，如果使用AOF 重写，那么AOF 文件中将只会保留下面一条命令</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>sadd animals &quot;dog&quot; &quot;tiger&quot; &quot;panda&quot; &quot;lion&quot; &quot;cat&quot;
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p><strong>也就是说 AOF 文件重写并不是对原文件进行重新整理，而是直接读取服务器现有的键值对，然后用一条命令去代替之前记录这个键值对的多条命令，生成一个新的文件后去替换原来的 AOF 文件</strong></p><p>AOF 文件重写触发机制：通过 redis.conf 配置文件中的 auto-aof-rewrite-percentage：默认值为100，以及auto-aof-rewrite-min-size：64mb 配置，也就是说默认Redis会记录上次重写时的AOF大小，<strong>默认配置是当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发</strong></p><p>Redis 是单线程工作，如果 重写 AOF 需要比较长的时间，那么在重写 AOF 期间，Redis将长时间无法处理其他的命令，这显然是不能忍受的。Redis为了克服这个问题，解决办法是将 AOF 重写程序放到子程序中进行，这样有两个好处：</p><p>① 子进程进行 AOF 重写期间，服务器进程（父进程）可以继续处理其他命令。</p><p>② 子进程带有父进程的数据副本，使用子进程而不是线程，可以在避免使用锁的情况下，保证数据的安全性</p><blockquote><p>redis解决重写时数据不一致的问题?</p><p>因为子进程在进行 AOF 重写期间，服务器进程依然在处理其它命令，这新的命令有可能也对数据库进行了修改操作，使得当前数据库状态和重写后的 AOF 文件状态不一致，</p><p>为了解决这个数据状态不一致的问题，Redis 服务器设置了一个 AOF 重写缓冲区，这个缓冲区是在创建子进程后开始使用，当Redis服务器执行一个写命令之后，就会将这个写命令也发送到 AOF 重写缓冲区。当子进程完成 AOF 重写之后，就会给父进程发送一个信号，父进程接收此信号后，就会调用函数将 AOF 重写缓冲区的内容都写到新的 AOF 文件中</p></blockquote><h5 id="_6-aof的优缺点" tabindex="-1"><a class="header-anchor" href="#_6-aof的优缺点" aria-hidden="true">#</a> 6. AOF的优缺点</h5><p>优点：</p><p>① AOF 持久化的方法提供了多种的同步频率，即使使用默认的同步频率每秒同步一次，Redis 最多也就丢失 1 秒的数据而已。</p><p>② AOF 文件使用 Redis 命令追加的形式来构造，因此，即使 Redis 只能向 AOF 文件写入命令的片断，使用 redis-check-aof 工具也很容易修正 AOF 文件。</p><p>③ AOF 文件的格式可读性较强，这也为使用者提供了更灵活的处理方式。例如，如果我们不小心错用了 FLUSHALL 命令，在重写还没进行时，我们可以手工将最后的 FLUSHALL 命令去掉，然后再使用 AOF 来恢复数据。</p><p>缺点：</p><p>① 对于具有相同数据的的 Redis，AOF 文件通常会比 RDB 文件体积更大。</p><p>② 虽然 AOF 提供了多种同步的频率，默认情况下，每秒同步一次的频率也具有较高的性能。但在 Redis 的负载较高时，RDB 比 AOF 具好更好的性能保证。</p><p>③ RDB 使用快照的形式来持久化整个 Redis 数据，而 AOF 只是将每次执行的命令追加到 AOF 文件中，因此从理论上说，RDB 比 AOF 方式更健壮。官方文档也指出，AOF 的确也存在一些 BUG，这些 BUG 在 RDB不存在。</p><h3 id="_8-3-持久化方案选择" tabindex="-1"><a class="header-anchor" href="#_8-3-持久化方案选择" aria-hidden="true">#</a> 8.3 持久化方案选择</h3><p>那么对于 AOF 和 RDB 两种持久化方式，我们应该如何选择呢？</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>如果可以忍受一小段时间内数据的丢失，毫无疑问使用 RDB 是最好的，定时生成 RDB 快照（snapshot）非常便于进行数据库备份， 并且 RDB 恢复数据集的速度也要比 AOF 恢复的速度要快，而且使用 RDB 还可以避免 AOF 一些隐藏的 bug；否则就使用 AOF 重写。但是一般情况下建议不要单独使用某一种持久化机制，而是应该两种一起用，在这种情况下,当redis重启的时候会优先载入AOF文件来恢复原始的数据，因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整。Redis后期官方可能都有将两种持久化方式整合为一种持久化模型
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><h3 id="_8-4-rdb-aof混合持久化" tabindex="-1"><a class="header-anchor" href="#_8-4-rdb-aof混合持久化" aria-hidden="true">#</a> 8.4 RDB-AOF混合持久化</h3><p>这里补充一个知识点，在Redis4.0之后，又新增了RDB-AOF混合持久化方式。这种方式结合了RDB和AOF的优点，既能快速加载又能避免丢失过多的数据。</p><p>具体配置为</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>aof-use-rdb-preamble yes   #设置为yes表示开启，设置为no表示禁用
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>当开启混合持久化时，主进程先fork出子进程将现有内存副本全量以RDB方式写入aof文件中，然后将缓冲区中的增量命令以AOF方式写入aof文件中，写入完成后通知主进程更新相关信息，并将新的含有 RDB和AOF两种格式的aof文件替换旧的aof文件。</p><p>简单来说：混合持久化方式产生的文件一部分是RDB格式，一部分是AOF格式</p><h2 id="redis主从复制" tabindex="-1"><a class="header-anchor" href="#redis主从复制" aria-hidden="true">#</a> Redis主从复制</h2><h4 id="_1-主从复制概述" tabindex="-1"><a class="header-anchor" href="#_1-主从复制概述" aria-hidden="true">#</a> 1.主从复制概述</h4><p>前面介绍Redis，我们都在一台服务器上进行操作的，也就是说读和写以及备份操作都是在一台Redis服务器上进行的，那么随着项目访问量的增加，对Redis服务器的操作也越加频繁，虽然Redis读写速度都很快，但是一定程度上也会造成一定的延时，那么为了解决访问量大的问题，通常会采取的一种方式是主从架构Master/Slave，Master 以写为主，Slave 以读为主，Master 主节点更新后根据配置，自动同步到从机Slave 节点</p><h4 id="_2-主从复制实验" tabindex="-1"><a class="header-anchor" href="#_2-主从复制实验" aria-hidden="true">#</a> 2.主从复制实验</h4><p>1、修改配置文件</p><p>首先将redis.conf 配置文件复制三份，通过修改端口分别模拟三台Redis服务器。</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>[root@localhost bin]## cp redis.conf 6379redis.conf
[root@localhost bin]## cp redis.conf 6380redis.conf
[root@localhost bin]## cp redis.conf 6381redis.conf
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>然后我们分别对这三个redis.conf 文件进行修改</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>daemonize yes
pidfile /var/run/redis_6379.pid    
port 6379
logfile &quot;6379.log&quot;
dbfilename &quot;dump6379.rdb&quot;
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>依次将 6380redis.conf 、6381redis.conf 配置一次，则配置完毕。然后分别启动这三个服务，并通过命令查看Redis是否启动</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>[root@localhost bin]## ./redis-server 6379redis.conf   #其它省略
[root@localhost bin]## ps -ef|grep redis
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div></div></div><p>接下来通过如下命令分别进入到这三个Redis客户端</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>[root@localhost bin]## ./redis-cli -p 6379
[root@localhost bin]## ./redis-cli -p 6380
[root@localhost bin]## ./redis-cli -p 6381
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>2、设置主从</p><p>① 通过 info replication 命令查看节点角色</p><p>我们发现这三个节点都是扮演的 Master 角色。那么如何将 6380 和 6381 节点变为 Slave 角色呢？</p><p>② 选择6380端口和6381端口，执行命令：SLAVEOF 127.0.0.1 6379</p><p>分别在三个会话窗口执行 info replication。这个时候6379是master 而6380和6381已经变成slave</p><p>这里通过命令来设置主从关系，一旦服务重启，那么角色关系将不复存在。想要永久的保存这种关系，可以通过配置redis.conf 文件来配置。</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>replicaof 127.0.0.1 6379     #老版本redis   slaveof 127.0.0.1 6379 
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>3、测试主从</p><p>① 增量复制</p><p>主节点执行 set k1 v1 命令，从节点 get k1 能获取吗？</p><p>② 全量复制</p><p>通过执行 replicaof 127.0.0.1 6379，如果主节点 6379 以前还存在一些 key，那么执行命令之后，从节点会将主节点master以前的信息也都复制过来吗？会</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>当从节点发出 SLAVEOF/replicaof命令，要求从服务器复制主服务器时，从服务器通过向主服务器发送 SYNC 命令来完成。该命令执行步骤：
1、从服务器向主服务器发送 SYNC 命令
2、收到 SYNC 命令的主服务器执行 BGSAVE 命令，在后台生成一个 RDB 文件，并使用一个缓冲区记录从开始执行的所有写命令
3、当主服务器的 BGSAVE 命令执行完毕时，主服务器会将 BGSAVE 命令生成的 RDB 文件发送给从服务器，从服务器接收此 RDB 文件，并将服务器状态更新为RDB文件记录的状态。
4、主服务器将缓冲区的所有写命令也发送给从服务器，从服务器执行相应命令
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>③ 主从读写分离</p><p>主节点能够执行写命令，从节点能够执行写命令吗？不行，原因是在配置文件 6381redis.conf 中对于 slave-read-only 的配置</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>replica-read-only yes
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>如果我们将其修改为 no 之后，执行写命令是可以的，但是从节点写命令的数据从节点或者主节点都不能获取的</p><p>④主节点宕机</p><p>主节点 Master 挂掉，两个从节点角色会发生变化吗？</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>127.0.0.1:6379&gt; SHUTDOWN 
exit    
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div></div></div><p>测试可知主节点 Master 挂掉之后，从节点角色还是不会改变的。</p><p>⑤ 主节点宕机后恢复</p><p>主节点Master挂掉之后，马上启动主机Master，主节点扮演的角色还是 Master 吗？测试发现主节点挂掉之后重启，又恢复了主节点的角色</p><h2 id="redis-和-boot-新整合" tabindex="-1"><a class="header-anchor" href="#redis-和-boot-新整合" aria-hidden="true">#</a> Redis 和 Boot 新整合</h2><h3 id="基础配置" tabindex="-1"><a class="header-anchor" href="#基础配置" aria-hidden="true">#</a> 基础配置</h3><h4 id="引入依赖" tabindex="-1"><a class="header-anchor" href="#引入依赖" aria-hidden="true">#</a> 引入依赖</h4><div class="language-xml line-numbers-mode" data-ext="xml"><pre class="language-xml"><code><span class="token comment">&lt;!--redis 依赖--&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
 <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>org.springframework.boot<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
 <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>spring-boot-starter-data-redis<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>
<span class="token comment">&lt;!--redis 连接池依赖 备用--&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>org.apache.commons<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>commons-pool2<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="yml-配置" tabindex="-1"><a class="header-anchor" href="#yml-配置" aria-hidden="true">#</a> yml 配置</h4><div class="language-yaml line-numbers-mode" data-ext="yml"><pre class="language-yaml"><code><span class="token key atrule">spring</span><span class="token punctuation">:</span>
    <span class="token key atrule">redis</span><span class="token punctuation">:</span>
        <span class="token comment">## Redis 服务器地址</span>
        <span class="token key atrule">host</span><span class="token punctuation">:</span> localhost
        <span class="token comment">## Redis 服务器连接端口</span>
        <span class="token key atrule">port</span><span class="token punctuation">:</span> <span class="token number">6379</span>
        <span class="token comment">## Redis 数据库索引（默认为 0）</span>
        <span class="token key atrule">database</span><span class="token punctuation">:</span> <span class="token number">0</span>
        <span class="token comment">## Redis 服务器连接密码（默认为空）</span>
        <span class="token key atrule">password</span><span class="token punctuation">:</span> <span class="token number">123</span>
        <span class="token comment">## Redis 连接池 | 以下非必须，有默认值</span>
        <span class="token key atrule">lettuce</span><span class="token punctuation">:</span>
            <span class="token key atrule">pool</span><span class="token punctuation">:</span>
                <span class="token comment">## 连接池最大连接数（使用负值表示没有限制）默认 8</span>
                <span class="token key atrule">max-active</span><span class="token punctuation">:</span> <span class="token number">8</span>
                <span class="token comment">## 连接池最大阻塞等待时间（使用负值表示没有限制）默认 -1</span>
                <span class="token key atrule">max-wait</span><span class="token punctuation">:</span> <span class="token number">-1</span>
                <span class="token comment">## 连接池中的最大空闲连接 默认 8</span>
                <span class="token key atrule">max-idle</span><span class="token punctuation">:</span> <span class="token number">8</span>
                <span class="token comment">## 连接池中的最小空闲连接 默认 0</span>
                <span class="token key atrule">min-idle</span><span class="token punctuation">:</span> <span class="token number">0</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="数据类型" tabindex="-1"><a class="header-anchor" href="#数据类型" aria-hidden="true">#</a> 数据类型</h4><table><thead><tr><th style="text-align:left;">专有操作</th><th style="text-align:left;">说明</th></tr></thead><tbody><tr><td style="text-align:left;">ValueOperations</td><td style="text-align:left;">string 类型的数据操作</td></tr><tr><td style="text-align:left;">ListOperations</td><td style="text-align:left;">list 类型的数据操作</td></tr><tr><td style="text-align:left;">SetOperations</td><td style="text-align:left;">set 类型数据操作</td></tr><tr><td style="text-align:left;">ZSetOperations</td><td style="text-align:left;">zset 类型数据操作</td></tr><tr><td style="text-align:left;">HashOperations</td><td style="text-align:left;">map 类型的数据操作</td></tr></tbody></table><h3 id="template-方式数据读写" tabindex="-1"><a class="header-anchor" href="#template-方式数据读写" aria-hidden="true">#</a> Template 方式数据读写</h3><h4 id="_1-redistemplate-注入" tabindex="-1"><a class="header-anchor" href="#_1-redistemplate-注入" aria-hidden="true">#</a> 1.RedisTemplate 注入</h4><blockquote><p>不推荐: 因为使用 不管什么类型的数据 都将会转化成字符串 导致在 redis数据库里 乱码</p></blockquote><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token annotation punctuation">@Autowired</span>
<span class="token keyword">private</span> <span class="token class-name">RedisTemplate</span> redisTemplate<span class="token punctuation">;</span>
<span class="token comment">// 使用泛型定义 key 和 value 的数据类型</span>
<span class="token keyword">private</span> <span class="token class-name">RedisTemplate</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span><span class="token class-name">String</span><span class="token punctuation">&gt;</span></span> redisTemplate<span class="token punctuation">;</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="_2-序列化-配置类注入" tabindex="-1"><a class="header-anchor" href="#_2-序列化-配置类注入" aria-hidden="true">#</a> 2.序列化 配置类注入</h4><blockquote><p>使用 序列化 配置类 可解决乱码问题</p></blockquote><div class="language-xml line-numbers-mode" data-ext="xml"><pre class="language-xml"><code><span class="token comment">&lt;!--redis 序列化 MVC自带--&gt;</span>
<span class="token comment">&lt;!--一般情况无需添加 序列化 配置类缺少转换时可添加--&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>com.fasterxml.jackson.core<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>jackson-databind<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h5 id="序列化工厂-配置类" tabindex="-1"><a class="header-anchor" href="#序列化工厂-配置类" aria-hidden="true">#</a> <strong>序列化工厂 配置类</strong></h5><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">com<span class="token punctuation">.</span>api<span class="token punctuation">.</span>config</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>context<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">Bean</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>context<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">Configuration</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>data<span class="token punctuation">.</span>redis<span class="token punctuation">.</span>connection<span class="token punctuation">.</span></span><span class="token class-name">RedisConnectionFactory</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>data<span class="token punctuation">.</span>redis<span class="token punctuation">.</span>core<span class="token punctuation">.</span></span><span class="token class-name">RedisTemplate</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>data<span class="token punctuation">.</span>redis<span class="token punctuation">.</span>serializer<span class="token punctuation">.</span></span><span class="token class-name">GenericJackson2JsonRedisSerializer</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>data<span class="token punctuation">.</span>redis<span class="token punctuation">.</span>serializer<span class="token punctuation">.</span></span><span class="token class-name">RedisSerializer</span></span><span class="token punctuation">;</span>

<span class="token annotation punctuation">@Configuration</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">RedisConfig</span> <span class="token punctuation">{</span>

    <span class="token annotation punctuation">@Bean</span>
    <span class="token keyword">public</span> <span class="token class-name">RedisTemplate</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">&gt;</span></span> <span class="token function">redisTemplate</span><span class="token punctuation">(</span><span class="token class-name">RedisConnectionFactory</span> redisConnectionFactory<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// 创建 Template</span>
        <span class="token class-name">RedisTemplate</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">&gt;</span></span> redisTemplate <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">RedisTemplate</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 设置连接工厂</span>
        redisTemplate<span class="token punctuation">.</span><span class="token function">setConnectionFactory</span><span class="token punctuation">(</span>redisConnectionFactory<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 设置序列化工具</span>
        <span class="token class-name">GenericJackson2JsonRedisSerializer</span> jsonRedisSerializer <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">GenericJackson2JsonRedisSerializer</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// key 和 hashkey 使用 string 序列化</span>
        redisTemplate<span class="token punctuation">.</span><span class="token function">setKeySerializer</span><span class="token punctuation">(</span><span class="token class-name">RedisSerializer</span><span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        redisTemplate<span class="token punctuation">.</span><span class="token function">setHashKeySerializer</span><span class="token punctuation">(</span><span class="token class-name">RedisSerializer</span><span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// value 和 hashvalue 使用 json 序列化</span>
        redisTemplate<span class="token punctuation">.</span><span class="token function">setValueSerializer</span><span class="token punctuation">(</span>jsonRedisSerializer<span class="token punctuation">)</span><span class="token punctuation">;</span>
        redisTemplate<span class="token punctuation">.</span><span class="token function">setHashValueSerializer</span><span class="token punctuation">(</span>jsonRedisSerializer<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> redisTemplate<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h5 id="opsforvalue-字符串" tabindex="-1"><a class="header-anchor" href="#opsforvalue-字符串" aria-hidden="true">#</a> opsForValue 字符串</h5><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token annotation punctuation">@Autowired</span>
<span class="token keyword">private</span> <span class="token class-name">RedisTemplate</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">&gt;</span></span> redisTemplate<span class="token punctuation">;</span>

<span class="token comment">// 存入 key 和 value 字符串</span>
redisTemplate<span class="token punctuation">.</span><span class="token function">opsForValue</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token string">&quot;key-键&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;value-内容&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 根据 key 获取 value</span>
<span class="token class-name">Object</span> value <span class="token operator">=</span> redisTemplate<span class="token punctuation">.</span><span class="token function">opsForValue</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">&quot;key-键&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 存入 key 和 对象</span>
redisTemplate<span class="token punctuation">.</span><span class="token function">opsForValue</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token string">&quot;key-键&quot;</span><span class="token punctuation">,</span> 对象<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 根据 key 获取 对象</span>
<span class="token class-name">Object</span> value <span class="token operator">=</span> redisTemplate<span class="token punctuation">.</span><span class="token function">opsForValue</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">&quot;key-键&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="_3-stringredistemplate-注入" tabindex="-1"><a class="header-anchor" href="#_3-stringredistemplate-注入" aria-hidden="true">#</a> 3.StringRedisTemplate 注入</h4><blockquote><p>推荐使用: 储存时不会造成乱码</p></blockquote><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token annotation punctuation">@Autowired</span>
<span class="token keyword">private</span> <span class="token class-name">StringRedisTemplate</span> stringRedisTemplate<span class="token punctuation">;</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div></div></div><h5 id="opsforvalue-字符串-1" tabindex="-1"><a class="header-anchor" href="#opsforvalue-字符串-1" aria-hidden="true">#</a> opsForValue 字符串</h5><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">com<span class="token punctuation">.</span>apai</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>junit<span class="token punctuation">.</span>jupiter<span class="token punctuation">.</span>api<span class="token punctuation">.</span></span><span class="token class-name">Test</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>beans<span class="token punctuation">.</span>factory<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">Autowired</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>boot<span class="token punctuation">.</span>test<span class="token punctuation">.</span>context<span class="token punctuation">.</span></span><span class="token class-name">SpringBootTest</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>data<span class="token punctuation">.</span>redis<span class="token punctuation">.</span>core<span class="token punctuation">.</span></span><span class="token class-name">RedisTemplate</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>data<span class="token punctuation">.</span>redis<span class="token punctuation">.</span>core<span class="token punctuation">.</span></span><span class="token class-name">StringRedisTemplate</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>data<span class="token punctuation">.</span>redis<span class="token punctuation">.</span>core<span class="token punctuation">.</span></span><span class="token class-name">ValueOperations</span></span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token import"><span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token class-name">ArrayList</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token class-name">HashMap</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token class-name">List</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token class-name">Map</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span>concurrent<span class="token punctuation">.</span></span><span class="token class-name">TimeUnit</span></span><span class="token punctuation">;</span>

<span class="token annotation punctuation">@SpringBootTest</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">RedisTest</span> <span class="token punctuation">{</span>

    <span class="token comment">// 存入redis会造成乱码</span>
    <span class="token annotation punctuation">@Autowired</span>
    <span class="token keyword">private</span> <span class="token class-name">RedisTemplate</span> redisTemplate<span class="token punctuation">;</span>

    <span class="token comment">// string 存入redis不会造成乱码</span>
    <span class="token annotation punctuation">@Autowired</span>
    <span class="token keyword">private</span> <span class="token class-name">StringRedisTemplate</span> stringRedisTemplate<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Test</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">testString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
        <span class="token class-name">ValueOperations</span> ops <span class="token operator">=</span> stringRedisTemplate<span class="token punctuation">.</span><span class="token function">opsForValue</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 添加一条数据 key - value</span>
        ops<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token string">&quot;name&quot;</span><span class="token punctuation">,</span><span class="token string">&quot;zhangsan&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 根据key加上过期时间 | key - 时间 _ 时间单位</span>
        stringRedisTemplate<span class="token punctuation">.</span><span class="token function">boundValueOps</span><span class="token punctuation">(</span><span class="token string">&quot;name&quot;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">expire</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">,</span> <span class="token class-name">TimeUnit</span><span class="token punctuation">.</span><span class="token constant">SECONDS</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 获取key过期时间</span>
        stringRedisTemplate<span class="token punctuation">.</span><span class="token function">getExpire</span><span class="token punctuation">(</span><span class="token string">&quot;name&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">// 根据key获取一条数据</span>
        <span class="token class-name">String</span> name <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">)</span> ops<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">&quot;name&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">// 使用map一次添加多条数据</span>
        <span class="token class-name">Map</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span><span class="token class-name">String</span><span class="token punctuation">&gt;</span></span> map <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">HashMap</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        map<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string">&quot;age&quot;</span><span class="token punctuation">,</span><span class="token string">&quot;20&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        map<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string">&quot;address&quot;</span><span class="token punctuation">,</span><span class="token string">&quot;sh&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        ops<span class="token punctuation">.</span><span class="token function">multiSet</span><span class="token punctuation">(</span>map<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">// 根据list的值获取多条数据</span>
        <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">&gt;</span></span> keys <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ArrayList</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        keys<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token string">&quot;name&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        keys<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token string">&quot;age&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        keys<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token string">&quot;address&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">List</span> list <span class="token operator">=</span> ops<span class="token punctuation">.</span><span class="token function">multiGet</span><span class="token punctuation">(</span>keys<span class="token punctuation">)</span><span class="token punctuation">;</span>
        list<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token operator">::</span><span class="token function">println</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">// 根据key删除一条数据</span>
        stringRedisTemplate<span class="token punctuation">.</span><span class="token function">delete</span><span class="token punctuation">(</span><span class="token string">&quot;age&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h2 id="redis-和-sping-boot-整合" tabindex="-1"><a class="header-anchor" href="#redis-和-sping-boot-整合" aria-hidden="true">#</a> redis 和 sping boot 整合</h2><p><strong>详见 sping boot 详解2</strong></p><blockquote><p>引入依赖</p><div class="language-xml line-numbers-mode" data-ext="xml"><pre class="language-xml"><code><span class="token comment">&lt;!--redis 依赖--&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
 <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>org.springframework.boot<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
 <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>spring-boot-starter-data-redis<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div></blockquote><blockquote><p>application 配置</p></blockquote><div class="language-yaml line-numbers-mode" data-ext="yml"><pre class="language-yaml"><code><span class="token comment">### Redis 服务器地址</span>
spring.redis.host=localhost
<span class="token comment">### Redis 服务器连接端口</span>
spring.redis.port=6379
<span class="token comment">### Redis 数据库索引（默认为 0）</span>
spring.redis.database=0
<span class="token comment">### Redis 服务器连接密码（默认为空）</span>
spring.redis.password=
<span class="token comment">### 以下非必须，有默认值</span>
<span class="token comment">### 连接池最大连接数（使用负值表示没有限制）默认 8</span>
spring.redis.lettuce.pool.max<span class="token punctuation">-</span>active=8
<span class="token comment">### 连接池最大阻塞等待时间（使用负值表示没有限制）默认 -1</span>
spring.redis.lettuce.pool.max<span class="token punctuation">-</span>wait=<span class="token punctuation">-</span><span class="token number">1</span>
<span class="token comment">### 连接池中的最大空闲连接 默认 8</span>
spring.redis.lettuce.pool.max<span class="token punctuation">-</span>idle=8
<span class="token comment">### 连接池中的最小空闲连接 默认 0</span>
spring.redis.lettuce.pool.min<span class="token punctuation">-</span>idle=0
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote><p>如果连接远程服务器，那么把redis服务器的配置文件的 bind 绑定服务器ip，或者是写成 bind 0.0.0.0</p></blockquote><p>Spring Data Redis 针对 api 进行了重新归类与封装，将同一类型的操作封装为 <strong>Operation</strong> 接口：</p><table><thead><tr><th style="text-align:left;">专有操作</th><th style="text-align:left;">说明</th></tr></thead><tbody><tr><td style="text-align:left;">ValueOperations</td><td style="text-align:left;">string 类型的数据操作</td></tr><tr><td style="text-align:left;">ListOperations</td><td style="text-align:left;">list 类型的数据操作</td></tr><tr><td style="text-align:left;">SetOperations</td><td style="text-align:left;">set 类型数据操作</td></tr><tr><td style="text-align:left;">ZSetOperations</td><td style="text-align:left;">zset 类型数据操作</td></tr><tr><td style="text-align:left;">HashOperations</td><td style="text-align:left;">map 类型的数据操作</td></tr></tbody></table><h3 id="template方式" tabindex="-1"><a class="header-anchor" href="#template方式" aria-hidden="true">#</a> Template方式</h3><h4 id="redistemplate方式" tabindex="-1"><a class="header-anchor" href="#redistemplate方式" aria-hidden="true">#</a> RedisTemplate方式</h4><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token comment">// RedisTemplate 方式</span>
<span class="token comment">// 不推荐: 因为使用 不管什么类型的数据 都将会转化成字符串 导致在 redis数据库里 乱码</span>
<span class="token annotation punctuation">@Autowired</span>
<span class="token keyword">private</span> <span class="token class-name">RedisTemplate</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span><span class="token class-name">String</span><span class="token punctuation">&gt;</span></span> redisTemplate<span class="token punctuation">;</span>

<span class="token annotation punctuation">@Override</span>
<span class="token keyword">public</span> <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">User</span><span class="token punctuation">&gt;</span></span> <span class="token function">findAllUser</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>

    <span class="token class-name">BoundValueOperations</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">String</span><span class="token punctuation">&gt;</span></span> stringTemplate  <span class="token operator">=</span> redisTemplate<span class="token punctuation">.</span><span class="token function">boundValueOps</span><span class="token punctuation">(</span><span class="token string">&quot;userlist&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">Object</span> str <span class="token operator">=</span> stringTemplate<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">User</span><span class="token punctuation">&gt;</span></span> users <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ArrayList</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">User</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">ObjectMapper</span> om <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ObjectMapper</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">try</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span><span class="token punctuation">(</span>str <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
            users <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>userMapper<span class="token punctuation">.</span><span class="token function">selectList</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token comment">//集合转成字符串</span>
            str <span class="token operator">=</span> om<span class="token punctuation">.</span><span class="token function">writeValueAsString</span><span class="token punctuation">(</span>users<span class="token punctuation">)</span><span class="token punctuation">;</span>
            redisTemplate<span class="token punctuation">.</span><span class="token function">boundValueOps</span><span class="token punctuation">(</span><span class="token string">&quot;userlist&quot;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span>str<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span><span class="token keyword">else</span><span class="token punctuation">{</span>
            <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;======从redis缓存中获得数据=========&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            users <span class="token operator">=</span> om<span class="token punctuation">.</span><span class="token function">readValue</span><span class="token punctuation">(</span>str<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span><span class="token keyword">new</span> <span class="token class-name">TypeReference</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">List</span><span class="token punctuation">&lt;</span><span class="token class-name">User</span><span class="token punctuation">&gt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token keyword">catch</span><span class="token punctuation">(</span><span class="token class-name">Exception</span> ex<span class="token punctuation">)</span><span class="token punctuation">{</span>
        ex<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">return</span> users<span class="token punctuation">;</span>

<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="stringredistemplate-方式" tabindex="-1"><a class="header-anchor" href="#stringredistemplate-方式" aria-hidden="true">#</a> StringRedisTemplate 方式</h4><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token comment">// StringRedisTemplate 方式 </span>
<span class="token comment">// 推荐使用</span>
<span class="token annotation punctuation">@Autowired</span>
<span class="token keyword">private</span> <span class="token class-name">StringRedisTemplate</span> redisTemplate<span class="token punctuation">;</span>

<span class="token annotation punctuation">@Override</span>
<span class="token keyword">public</span> <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">User</span><span class="token punctuation">&gt;</span></span> <span class="token function">findAllUser</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Exception</span> <span class="token punctuation">{</span>
    <span class="token class-name">ObjectMapper</span> objectMapper <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ObjectMapper</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">BoundValueOperations</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">String</span><span class="token punctuation">&gt;</span></span> userlist <span class="token operator">=</span> redisTemplate<span class="token punctuation">.</span><span class="token function">boundValueOps</span><span class="token punctuation">(</span><span class="token string">&quot;userlist&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">String</span> s <span class="token operator">=</span> userlist<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">User</span><span class="token punctuation">&gt;</span></span> userList<span class="token operator">=</span><span class="token keyword">null</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span><span class="token punctuation">(</span>s<span class="token operator">!=</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
        userList <span class="token operator">=</span> objectMapper<span class="token punctuation">.</span><span class="token function">readValue</span><span class="token punctuation">(</span>s<span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">TypeReference</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">List</span><span class="token punctuation">&lt;</span><span class="token class-name">User</span><span class="token punctuation">&gt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> userList<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    userList <span class="token operator">=</span> userMapper<span class="token punctuation">.</span><span class="token function">selectList</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">// 将查询的集合存入rides里</span>
    userlist<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span>objectMapper<span class="token punctuation">.</span><span class="token function">writeValueAsString</span><span class="token punctuation">(</span>userList<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> userList<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="常用-api" tabindex="-1"><a class="header-anchor" href="#常用-api" aria-hidden="true">#</a> 常用 - API</h4><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token annotation punctuation">@Autowired</span>
<span class="token keyword">private</span> <span class="token class-name">StringRedisTemplate</span> redisTemplate<span class="token punctuation">;</span>

<span class="token comment">// 储存 字符串 数据</span>
<span class="token class-name">BoundValueOperations</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">String</span><span class="token punctuation">&gt;</span></span> ops <span class="token operator">=</span> redisTemplate<span class="token punctuation">.</span><span class="token function">boundValueOps</span><span class="token punctuation">(</span><span class="token string">&quot;键&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
ops<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token string">&quot;值&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 储存 hash 对象</span>
<span class="token class-name">BoundHashOperations</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">&gt;</span></span> hash <span class="token operator">=</span> redisTemplate<span class="token punctuation">.</span><span class="token function">boundHashOps</span><span class="token punctuation">(</span><span class="token string">&quot;hash-pai&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
hash<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string">&quot;name&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;小九&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
hash<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string">&quot;xianqun&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;仙裙&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="序列化" tabindex="-1"><a class="header-anchor" href="#序列化" aria-hidden="true">#</a> 序列化</h4><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token comment">// 序列化</span>
<span class="token class-name">ObjectMapper</span> objectMapper <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ObjectMapper</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 根据键获取实例</span>
<span class="token class-name">BoundValueOperations</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">String</span><span class="token punctuation">&gt;</span></span> userlist <span class="token operator">=</span> redisTemplate<span class="token punctuation">.</span><span class="token function">boundValueOps</span><span class="token punctuation">(</span><span class="token string">&quot;userlist&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 根据实例获取已被序列化的列表的字符串</span>
<span class="token class-name">String</span> s <span class="token operator">=</span> userlist<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 将已被序列化的列表的字符串转为 list</span>
userList <span class="token operator">=</span> objectMapper<span class="token punctuation">.</span><span class="token function">readValue</span><span class="token punctuation">(</span>s<span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">TypeReference</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">List</span><span class="token punctuation">&lt;</span><span class="token class-name">User</span><span class="token punctuation">&gt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 将list序列化成字符串储存至内存数据库</span>
userlist<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span>objectMapper<span class="token punctuation">.</span><span class="token function">writeValueAsString</span><span class="token punctuation">(</span>userList<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="各类型实践" tabindex="-1"><a class="header-anchor" href="#各类型实践" aria-hidden="true">#</a> 各类型实践</h4><h5 id="_1-string字符串" tabindex="-1"><a class="header-anchor" href="#_1-string字符串" aria-hidden="true">#</a> 1 String字符串</h5><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token annotation punctuation">@Slf4j</span>
<span class="token annotation punctuation">@Test</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">testObj</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token class-name">ValueOperations</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">String</span><span class="token punctuation">&gt;</span></span> operations <span class="token operator">=</span> redisTemplate<span class="token punctuation">.</span><span class="token function">opsForValue</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    operations<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token string">&quot;id&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;9527&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    operations<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token string">&quot;name&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;tom&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    operations<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token string">&quot;age&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;21&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">String</span> name <span class="token operator">=</span> operations<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">&quot;name&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    log<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">&quot;{}&quot;</span><span class="token punctuation">,</span> name<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>key的自动过期问题，Redis 在存入每一个数据的时候都可以设置一个超时间，过了这个时间就会自动删除数据。</p><p>新建一个 Student 对象，存入 Redis 的同时设置 100 毫秒后失效，设置一个线程暂停 1000 毫秒之后，判断数据是否存在并打印结果。</p><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token annotation punctuation">@Test</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">testExpire</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">InterruptedException</span> <span class="token punctuation">{</span>
    <span class="token keyword">final</span> <span class="token class-name">String</span> key <span class="token operator">=</span> <span class="token string">&quot;expire&quot;</span> <span class="token punctuation">;</span>
    <span class="token class-name">Student</span> user <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Student</span><span class="token punctuation">(</span><span class="token string">&quot;tom&quot;</span><span class="token punctuation">,</span> <span class="token number">20</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">ValueOperations</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">Student</span><span class="token punctuation">&gt;</span></span> operations <span class="token operator">=</span> redisTemplate<span class="token punctuation">.</span><span class="token function">opsForValue</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> 
    operations<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> user<span class="token punctuation">,</span> <span class="token number">100</span><span class="token punctuation">,</span> <span class="token class-name">TimeUnit</span><span class="token punctuation">.</span><span class="token constant">MILLISECONDS</span><span class="token punctuation">)</span><span class="token punctuation">;</span>  <span class="token comment">// 这背后就有 Serializer 在工作</span>

    <span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">sleep</span><span class="token punctuation">(</span><span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">boolean</span> exists <span class="token operator">=</span> redisTemplate<span class="token punctuation">.</span><span class="token function">hasKey</span><span class="token punctuation">(</span>key<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span> exists <span class="token operator">?</span> <span class="token string">&quot;exists is true&quot;</span> <span class="token operator">:</span> <span class="token string">&quot;exists is false&quot;</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>从结果可以看出，Reids 中已经不存在 Student 对象了，此数据已经过期，同时我们在这个测试的方法中使用了 <em><code>hasKey(&quot;expire&quot;)</code></em> 方法，可以判断 key 是否存在</p><p>3、删除数据</p><p>有些时候，我们需要对过期的缓存进行删除，下面来测试此场景的使用。首先 set 一个字符串 <code>hello world</code>，紧接着删除此 key 的值，再进行判断。</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>redisTemplate.delete(&quot;key&quot;);
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><h5 id="_2-hash-哈希" tabindex="-1"><a class="header-anchor" href="#_2-hash-哈希" aria-hidden="true">#</a> 2 Hash（哈希）</h5><p>一般我们存储一个键，很自然的就会使用 get/set 去存储，实际上这并不是很好的做法。Redis 存储一个 key 会有一个最小内存，不管你存的这个键多小，都不会低于这个内存，因此合理的使用 Hash 可以帮我们节省很多内存。</p><p>Hash Set 就在哈希表 Key 中的域（Field）的值设为 value。如果 Key 不存在，一个新的哈希表被创建并进行 HSET 操作;如果域（field）已经存在于哈希表中，旧值将被覆盖。</p><p>先来看 Redis 对 Pojo 的支持，新建一个 Student 对象（需要实现 Serializable 接口），放到缓存中，再取出来。</p><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token annotation punctuation">@Test</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">testHash</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">final</span> <span class="token class-name">String</span> key <span class="token operator">=</span> <span class="token string">&quot;tom&quot;</span><span class="token punctuation">;</span> 

    <span class="token class-name">HashOperations</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">&gt;</span></span> hash <span class="token operator">=</span> redisTemplate<span class="token punctuation">.</span><span class="token function">opsForHash</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    hash<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> <span class="token string">&quot;name&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;tom&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    hash<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> <span class="token string">&quot;age&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;20&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token class-name">String</span> value <span class="token operator">=</span> hash<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> <span class="token string">&quot;name&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    log<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">&quot;hash value : {}&quot;</span><span class="token punctuation">,</span> value<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>输出结果:</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>hash value :tom
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>根据上面测试用例发现，Hash set 的时候需要传入三个参数，第一个为 key，第二个为 field，第三个为存储的值。一般情况下 Key 代表一组数据，field 为 key 相关的属性，而 value 就是属性对应的值。</p><h5 id="_3-list集合类型" tabindex="-1"><a class="header-anchor" href="#_3-list集合类型" aria-hidden="true">#</a> 3 List集合类型</h5><p>Redis List 的应用场景非常多，也是 Redis 最重要的数据结构之一。 使用 List 可以轻松的实现一个队列， List 典型的应用场景就是消息队列，可以利用 List 的 Push 操作，将任务存在 List 中，然后工作线程再用 POP 操作将任务取出进行执行。</p><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token annotation punctuation">@Test</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">testList</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">final</span> <span class="token class-name">String</span> key <span class="token operator">=</span> <span class="token string">&quot;list&quot;</span><span class="token punctuation">;</span>
    <span class="token class-name">ListOperations</span><span class="token operator">&lt;</span><span class="token class-name">String</span>， <span class="token class-name">String</span><span class="token operator">&gt;</span> list <span class="token operator">=</span> redisTemplate<span class="token punctuation">.</span><span class="token function">opsForList</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    list<span class="token punctuation">.</span><span class="token function">leftPush</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> <span class="token string">&quot;hello&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    list<span class="token punctuation">.</span><span class="token function">leftPush</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> <span class="token string">&quot;world&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    list<span class="token punctuation">.</span><span class="token function">leftPush</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> <span class="token string">&quot;goodbye&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">String</span> value <span class="token operator">=</span> list<span class="token punctuation">.</span><span class="token function">leftPop</span><span class="token punctuation">(</span>key<span class="token punctuation">)</span><span class="token punctuation">;</span>

    log<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">&quot;list value : {}&quot;</span><span class="token punctuation">,</span> value<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>输出结果</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>list value :goodbye
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>上面的例子我们从左侧插入一个 key 为 &quot;list&quot; 的队列，然后取出左侧最近的一条数据。其实 List 有很多 API 可以操作，比如从右侧进行插入队列，从右侧进行读取，或者通过方法 range 读取队列的一部分。接着上面的例子我们使用 range 来读取。</p><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">&gt;</span></span> values <span class="token operator">=</span> list<span class="token punctuation">.</span><span class="token function">range</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">String</span> v <span class="token operator">:</span> values<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;list range :&quot;</span> <span class="token operator">+</span> v<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>输出结果:</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>list range :goodbye
list range :world
list range :hello
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>range 后面的两个参数就是插入数据的位置，输入不同的参数就可以取出队列中对应的数据。</p><p>Redis List 的实现为一个双向链表，即可以支持反向查找和遍历，更方便操作，不过带来了部分额外的内存开销，Redis 内部的很多实现，包括发送缓冲队列等也都是用的这个数据结构。</p><h5 id="_4-set集合类型" tabindex="-1"><a class="header-anchor" href="#_4-set集合类型" aria-hidden="true">#</a> 4 Set集合类型</h5><p>Redis Set 对外提供的功能与 List 类似，是一个列表的功能，特殊之处在于 Set 是可以自动排重的，当你需要存储一个列表数据，又不希望出现重复数据时，Set 是一个很好的选择，并且 Set 提供了判断某个成员是否在一个 Set 集合内的重要接口，这个也是 List 所不能提供的。</p><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token annotation punctuation">@Test</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">testSet</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">final</span> <span class="token class-name">String</span> key <span class="token operator">=</span> <span class="token string">&quot;set&quot;</span><span class="token punctuation">;</span>
    <span class="token class-name">SetOperations</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">String</span><span class="token punctuation">&gt;</span></span> set <span class="token operator">=</span> redisTemplate<span class="token punctuation">.</span><span class="token function">opsForSet</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    set<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> <span class="token string">&quot;hello&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    set<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> <span class="token string">&quot;world&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    set<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> <span class="token string">&quot;world&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    set<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> <span class="token string">&quot;goodbye&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">Set</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">&gt;</span></span> values <span class="token operator">=</span> set<span class="token punctuation">.</span><span class="token function">members</span><span class="token punctuation">(</span>key<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">String</span> v <span class="token operator">:</span> values<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;set value :&quot;</span> <span class="token operator">+</span> v<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>输出结果:</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>set value :hello
set value :world
set value :goodbye
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>通过上面的例子我们发现，输入了两个相同的值 <code>world</code>，全部读取的时候只剩下了一条，说明 Set 对队列进行了自动的排重操作。另外，Redis 为集合提供了求交集、并集、差集等操作，可以非常方便的使用，这里就不一一举例了。</p><h5 id="_5-zset集合类型" tabindex="-1"><a class="header-anchor" href="#_5-zset集合类型" aria-hidden="true">#</a> 5 ZSet集合类型</h5><p>Redis Sorted Set 的使用场景与 Set 类似，区别是 Set 不是自动有序的，而 Sorted Set 可以通过用户额外提供一个优先级（Score）的参数来为成员排序，并且是插入有序，即自动排序。</p><p>在使用 Zset 的时候需要额外的输入一个参数 Score，Zset 会自动根据 Score 的值对集合进行排序，我们可以利用这个特性来做具有权重的队列，比如普通消息的 Score 为 1，重要消息的 Score 为 2，然后工作线程可以选择按 Score 的倒序来获取工作任务。</p><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token annotation punctuation">@Test</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">testZset</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">final</span> <span class="token class-name">String</span> key <span class="token operator">=</span> <span class="token string">&quot;zset&quot;</span><span class="token punctuation">;</span>
    redisTemplate<span class="token punctuation">.</span><span class="token function">delete</span><span class="token punctuation">(</span>key<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">ZSetOperations</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">String</span><span class="token punctuation">&gt;</span></span> zset <span class="token operator">=</span> redisTemplate<span class="token punctuation">.</span><span class="token function">opsForZSet</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    zset<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> <span class="token string">&quot;hello&quot;</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    zset<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> <span class="token string">&quot;world&quot;</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    zset<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> <span class="token string">&quot;good&quot;</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    zset<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> <span class="token string">&quot;bye&quot;</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token class-name">Set</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">&gt;</span></span> zsets <span class="token operator">=</span> zset<span class="token punctuation">.</span><span class="token function">range</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">String</span> v <span class="token operator">:</span> zsets<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        log<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">&quot;zset-A value : {}&quot;</span><span class="token punctuation">,</span> v<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token class-name">Set</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">&gt;</span></span> zsetB <span class="token operator">=</span> zset<span class="token punctuation">.</span><span class="token function">rangeByScore</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">String</span> v <span class="token operator">:</span> zsetB<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        log<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">&quot;zset-B value : {}&quot;</span><span class="token punctuation">,</span> v<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>   
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>输出结果:</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>zset-A value : hello
zset-A value : bye
zset-A value : good
zset-A value : world
zset-B value : hello
zset-B value : bye
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="redis-repositories方式" tabindex="-1"><a class="header-anchor" href="#redis-repositories方式" aria-hidden="true">#</a> Redis Repositories方式</h3><blockquote><p>Spring Data Redis 从 1.7 开始提供 Redis Repositories ，可以无缝的转换并存储 domain objects，使用的数据类型为哈希（hash）。</p><p>Spring Data Redis 的 Repository 的基本实现为：<strong>CrudRepository</strong> 。</p><p>基础用法（Usage）分为以下三步：</p></blockquote><h4 id="_1-启用-repository-功能" tabindex="-1"><a class="header-anchor" href="#_1-启用-repository-功能" aria-hidden="true">#</a> <strong>1.启用 Repository 功能</strong></h4><p>在启动类上加上注解 @EnableRedisRepositories(basePackages = &quot;com.woniu.outlet.redis&quot;)</p><blockquote><p>属性 <em><strong><code>basePackages</code></strong></em> 如果不赋值，那么默认是扫描入口类平级及之下的所有类，看它们谁的头上有 <em><strong><code>@Repository</code></strong></em> 注解。如果是同时使用 spring-data-jpa 和 spring-data-redis 时，由于它们的 Repository 的祖先中都有 CrudRepository 因此会造成冲突。虽有，最好还是加上 <em><strong><code>basePackages</code></strong></em> 属性并为它赋值，指定各自扫描的路径，以避免冲突</p></blockquote><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token annotation punctuation">@SpringBootApplication</span>
<span class="token comment">// 创建repository接口的代理对象</span>
<span class="token annotation punctuation">@EnableRedisRepositories</span><span class="token punctuation">(</span>basePackages <span class="token operator">=</span> <span class="token string">&quot;com.woniu.outlet.redis&quot;</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">K15ManagerApplication</span> <span class="token punctuation">{</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">SpringApplication</span><span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span><span class="token class-name">K15ManagerApplication</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">,</span> args<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h5 id="_2-注解需要缓存的实体" tabindex="-1"><a class="header-anchor" href="#_2-注解需要缓存的实体" aria-hidden="true">#</a> 2.注解需要缓存的实体</h5><p>添加关键的两个注解 <em><strong><code>@RedisHash</code></strong></em> 和 <em><strong><code>@Id</code></strong></em> ;</p><p>redis 储存为 hash 类型 外键为 @RedisHash(&quot;外键名&quot;) 内键名为 外键名 : id 包含实体类的数据对象</p><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token annotation punctuation">@Data</span>
<span class="token annotation punctuation">@RedisHash</span><span class="token punctuation">(</span><span class="token string">&quot;user&quot;</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">User</span> <span class="token keyword">implements</span> <span class="token class-name">Serializable</span> <span class="token punctuation">{</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token keyword">long</span> serialVersionUID <span class="token operator">=</span> <span class="token number">1L</span><span class="token punctuation">;</span>
    <span class="token annotation punctuation">@Id</span>
    <span class="token keyword">private</span> <span class="token class-name">Long</span> id<span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> userName<span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> password<span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> email<span class="token punctuation">;</span>
    <span class="token comment">//当然我们也可以定义集合</span>
    <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span>XX<span class="token punctuation">&gt;</span></span> lists<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><table><thead><tr><th style="text-align:left;">注解</th><th style="text-align:left;">说明</th></tr></thead><tbody><tr><td style="text-align:left;">@RedisHash</td><td style="text-align:left;">表示将 User 类的对象都对于 Redis 中的名为 user 的 Set 中。</td></tr><tr><td style="text-align:left;">@Id</td><td style="text-align:left;">标注于对象的唯一性标识上。</td></tr></tbody></table><p>如果将多个 User 对象通过 Repository 存储于 Redis 中，那么，它们每个的 key 分别是：*<strong><code>user:&lt;Id&gt;</code></strong> 。例如：<code>user:1</code>、<code>user:2</code>、<code>user:3</code>、...</p><p>获取它们每个对象的属性的命令为：</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>hget user:1 userName
hget user:1 lists.[0].属性
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div></div></div><h5 id="_3-创建repository-接口" tabindex="-1"><a class="header-anchor" href="#_3-创建repository-接口" aria-hidden="true">#</a> 3.创建Repository 接口</h5><p>自定的 Repository 接口必须继承 CrudRepository，才能“天生”具有存取数据的能力。</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>public interface RedisUserRepo extends CrudRepository&lt;User,Integer&gt; {
}
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div></div></div><p><img src="https://apaiimages.oss-cn-guangzhou.aliyuncs.com/MD/image-20220625164939902.png" alt="image-20220625164939902"></p><h5 id="_4-业务层-测试" tabindex="-1"><a class="header-anchor" href="#_4-业务层-测试" aria-hidden="true">#</a> 4.业务层 测试</h5><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token annotation punctuation">@Autowired</span>
<span class="token keyword">private</span> <span class="token class-name">UserRepository</span> userRepository<span class="token punctuation">;</span>

<span class="token comment">// 根据 Repository 接口 指定的实体类 内存数据库查询所有 集合时需强转</span>
<span class="token punctuation">(</span><span class="token class-name">List</span><span class="token punctuation">)</span> userRepository<span class="token punctuation">.</span><span class="token function">findAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> 


<span class="token comment">// 内存数据库 添加对应的实体类数据 已存在时 可以进行修改</span>
userRepository<span class="token punctuation">.</span><span class="token function">save</span><span class="token punctuation">(</span>user<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 内存数据库 根据 id 删除对应的数据</span>
userRepository<span class="token punctuation">.</span><span class="token function">deleteById</span><span class="token punctuation">(</span>id<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 集合列表存入 内存数据库</span>
userRepository<span class="token punctuation">.</span><span class="token function">saveAll</span><span class="token punctuation">(</span>listall<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h2 id="redis的缓存失效问题" tabindex="-1"><a class="header-anchor" href="#redis的缓存失效问题" aria-hidden="true">#</a> redis的缓存失效问题</h2><h3 id="_1、缓存雪崩" tabindex="-1"><a class="header-anchor" href="#_1、缓存雪崩" aria-hidden="true">#</a> 1、缓存雪崩</h3><p><strong>场景：</strong></p><p>如果所有首页的Key失效时间都是12小时，中午12点刷新的，我零点有个秒杀活动大量用户涌入，假设当时每秒 6000 个请求，本来缓存在可以扛住每秒 5000 个请求，但是缓存当时所有的Key都失效了。此时 1 秒 6000 个请求全部落数据库，数据库必然扛不住，它会报一下警，真实情况可能DBA都没反应过来就直接挂了。此时，如果没用什么特别的方案来处理这个故障，DBA 很着急，重启数据库，但是数据库立马又被新的流量给打死了</p><p><strong>解决方法:</strong></p><p>处理缓存雪崩简单，在批量往Redis存数据的时候，把每个Key的失效时间都加个随机值就好了，这样可以保证数据不会在同一时间大面积失效，</p><div class="language-text line-numbers-mode" data-ext="text"><pre class="language-text"><code>setRedis（Key，value，time + Math.random() * 10000）；
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>如果<strong>Redis</strong>是集群部署，将热点数据均匀分布在不同的<strong>Redis</strong>库中也能避免全部失效的问题，或者设置热点数据永远不过期</p><h3 id="_2、缓存穿透" tabindex="-1"><a class="header-anchor" href="#_2、缓存穿透" aria-hidden="true">#</a> 2、缓存穿透</h3><p>缓存穿透是指缓存和数据库中都没有的数据，而用户不断发起请求，如我们数据库的 id 都是1开始自增上去的，这个时候发起为id值为 -1 的数据或 id 为特别大不存在的数据。这时的用户很可能是攻击者，攻击会导致数据库压力过大，严重会击垮数据库，<strong>像这种你如果不对参数做校验，数据库id都是大于0的，我一直用小于0的参数去请求你，每次都能绕开Redis直接打到数据库，数据库也查不到，每次都这样，并发高点就容易崩掉了</strong></p><p>处理缓存穿透的方式很简单：在接口层增加校验，比如用户鉴权校验，参数做校验，不合法的参数直接代码Return，比如：id 做基础校验，id &lt;=0的直接拦截等，或者也可以将对应Key的Value对写为null，还有就是Redis一个高级用法**布隆过滤器（Bloom Filter）**这个也能很好的防止缓存穿透的发生，他的原理也很简单就是利用高效的数据结构和算法快速判断出你这个Key是否在数据库中存在，不存在你return就好了，存在你就去查了DB刷新KV再return</p><h3 id="_3、缓存击穿" tabindex="-1"><a class="header-anchor" href="#_3、缓存击穿" aria-hidden="true">#</a> 3、缓存击穿</h3><p>缓存击穿是指一个Key非常热点，在不停的扛着大并发，大并发集中对这一个点进行访问，当这个Key在失效的瞬间，持续的大并发就穿破缓存，直接请求数据库，就像在一个完好无损的桶上凿开了一个洞</p><blockquote><p>缓存穿透类似偷袭，绕过redis，袭击数据库。缓存击穿类似正面硬刚，一直进攻一个地方，直到失效时一起涌入攻击数据库。缓存雪崩类似鬼子进村</p></blockquote><p>缓存击穿的方案：设置热点数据永远不过期。分布式锁就能搞定了</p><h2 id="缓存与数据库一致性" tabindex="-1"><a class="header-anchor" href="#缓存与数据库一致性" aria-hidden="true">#</a> 缓存与数据库一致性</h2><h3 id="cache-aside-pattern" tabindex="-1"><a class="header-anchor" href="#cache-aside-pattern" aria-hidden="true">#</a> Cache Aside Pattern</h3><p>标准的方案，facebook 就是使用这种方式。</p><table><thead><tr><th>核心概念</th><th>说明</th></tr></thead><tbody><tr><td>失效</td><td>应用程序先从 cache 取数据，没有得到，则从数据库中取数据，成功后，放到缓存中。</td></tr><tr><td>命中</td><td>应用程序从 cache 中取数据，取到后返回。</td></tr><tr><td>更新</td><td>先把数据存到数据库中，成功后，再让缓存失效。</td></tr></tbody></table><h4 id="_1-1-读流程" tabindex="-1"><a class="header-anchor" href="#_1-1-读流程" aria-hidden="true">#</a> 1.1 读流程</h4><table><thead><tr><th>步骤</th><th>说明</th></tr></thead><tbody><tr><td>1</td><td>读缓存，命中则直接返回</td></tr><tr><td>2</td><td>如果没命中，读数据库</td></tr><tr><td>3</td><td>更新缓存</td></tr></tbody></table><h4 id="_1-2-写流程" tabindex="-1"><a class="header-anchor" href="#_1-2-写流程" aria-hidden="true">#</a> 1.2 写流程</h4><table><thead><tr><th>步骤</th><th>说明</th></tr></thead><tbody><tr><td>1</td><td>更新数据库</td></tr><tr><td>2</td><td>删缓存，使缓存失效</td></tr></tbody></table><p>先更新数据库，在删除缓存</p><h3 id="双写读写并发问题" tabindex="-1"><a class="header-anchor" href="#双写读写并发问题" aria-hidden="true">#</a> 双写读写并发问题</h3><p>Cache Aside Pattern 方案能解决 <code>双写并发</code> 问题：结论：<strong>即写完操作，就删除对应的redis缓存</strong></p><h4 id="先更新数据库-再更新缓存场景-不推荐" tabindex="-1"><a class="header-anchor" href="#先更新数据库-再更新缓存场景-不推荐" aria-hidden="true">#</a> 先更新数据库，再更新缓存场景-不推荐</h4><p>当有两个线程A、B，同时对一条数据进行操作，一开始数据库和redis的数据都为1，当线程A去修改数据库，将1改为2，然后线程A在修改缓存中的数据，可能因为网络原因出现延迟，这个时候线程B将数据库的2修改成了3、然后将redis中的1也改成了3，然后线程A恢复正常，将redis中的缓存改成了2，此时就出现了缓存数据和数据库数据不一致情况。<strong>不推荐</strong><img src="https://apaiimages.oss-cn-guangzhou.aliyuncs.com/MD/image-20211023094213033.png" alt=" "></p><h4 id="先更新缓存-再更新数据库场景-不推荐" tabindex="-1"><a class="header-anchor" href="#先更新缓存-再更新数据库场景-不推荐" aria-hidden="true">#</a> 先更新缓存，再更新数据库场景-不推荐</h4><p>当有两个线程A、B，同时对一条数据进行操作，线程A先将redis中的数据修改为了2，然后CPU切换到了线程B，将redis中的数据修改为了3，然后将数据库中的信息也修改了3，然后线程A获得CPU执行，将数据库中的信息改为了2，此时出现缓存和数据库数据不一致情况。不推荐</p><p><img src="https://apaiimages.oss-cn-guangzhou.aliyuncs.com/MD/image-20211023094755926.png" alt="image-20211023094755926"></p><h4 id="先删除缓存-再更新数据库的场景-不推荐" tabindex="-1"><a class="header-anchor" href="#先删除缓存-再更新数据库的场景-不推荐" aria-hidden="true">#</a> 先删除缓存，再更新数据库的场景-不推荐</h4><p>先删除缓存，再更新数据库能解决双写并发问题，不能解决读写并发问题。</p><p>读写问题</p><p>当有两个线程A、B，同时对一条数据进行操作，当线程A进行修改缓存操作时，先删除掉缓存中的数据，然后去修改数据库，因为网络问题出现延迟，这时线程B查新redis没有值，因此去数据库中查询数据为1，然后将数据1更新到缓存中，线程A网络恢复，又将数据库数据修改为了2，此时出现数据不一致。不推荐，这种情况在读写并发情况有问题 <img src="https://apaiimages.oss-cn-guangzhou.aliyuncs.com/MD/image-20211023095153207.png" alt="image-20211023095153207"></p><h4 id="先更新数据库-再删除缓存场景-可以接受" tabindex="-1"><a class="header-anchor" href="#先更新数据库-再删除缓存场景-可以接受" aria-hidden="true">#</a> 先更新数据库，再删除缓存场景-可以接受</h4><p>FaceBook 是采用这种方式，简称CAP</p><h5 id="两次修改-双写-场景" tabindex="-1"><a class="header-anchor" href="#两次修改-双写-场景" aria-hidden="true">#</a> 两次修改（双写）场景</h5><p>当有两个线程A、B，线程A去修改数据库中的值改为2，然后出现网络波动，线程B将数库中的值修改为了3，<strong>然后两个线程都会删除缓存，保证数据一致性</strong>。无非是线程A多删了一次</p><p><img src="https://apaiimages.oss-cn-guangzhou.aliyuncs.com/MD/image-20211023124410658.png" alt="image-20211023124410658"></p><h5 id="一改一查-读写-场景" tabindex="-1"><a class="header-anchor" href="#一改一查-读写-场景" aria-hidden="true">#</a> 一改一查（读写）场景</h5><p>场景1：</p><p>当有两个线程A、B，线程A先去将数据库的值修改为2，然后需要去删除redis中的缓存，当线程B去读取缓存时，线程A已经完成delete操作时，缓存不命中，需要去查询数据库，然后在更新缓存，数据一致性；</p><p>如果线程A没有完成delete操作（图中案例），线程B直接命中，返回的数据与数据库中的数据不一致，<strong>可能会短暂出现数据不一致情况</strong>，但最终都会一致</p><p><img src="https://apaiimages.oss-cn-guangzhou.aliyuncs.com/MD/image-20211023100120474.png" alt="image-20211023100120474"></p><p>场景2：</p><p>（0）缓存刚好失效，（1）线程A查询数据库，得一个旧值 ，（2）线程B将新值写入数据库，（3）线程B删除缓存（其实缓存这个时候没有东西，不过也无所谓，只不过删除的返回值为0而已），（5）最后线程A将查到的旧值写入缓存</p><p><img src="https://apaiimages.oss-cn-guangzhou.aliyuncs.com/MD/image-20211023124951584.png" alt="image-20211023124951584"></p><p>**然而，发生这种情况的概率又有多少呢？**发生上述情况有一个先天性条件，就是步骤（2）的写数据库操作比步骤（2）的读数据库操作耗时更短，才有可能使得步骤（4）先于步骤（5）。</p><p>可是，大家想想，数据库的读操作的速度远快于写操作的（不然做读写分离干嘛，做读写分离的意义就是因为读操作比较快，耗资源少），因此步骤（3）耗时比步骤（2）更短，这一情形很难出现。 假设，有人非要抬杠，有强迫症，一定要解决怎么办？</p><h3 id="cache-aside-pattern-方案" tabindex="-1"><a class="header-anchor" href="#cache-aside-pattern-方案" aria-hidden="true">#</a> Cache Aside Pattern 方案</h3><p>这个方案足够简单，容易理解，容易实现。只是面对『<strong>部分读写并发问题无能为力</strong>』，不过，实际上出现这种概率可能非常低，因为这个条件需要发生在读缓存时缓存失效，而且并发着有一个写操作。而实际上数据库的写操作会比读操作慢得多，而且还要锁表，而读操作必需在写操作前进入数据库操作，而又要晚于写操作更新缓存，所有的这些条件都具备的概率基本并不大。</p><p>1、相关pom</p><div class="language-xml line-numbers-mode" data-ext="xml"><pre class="language-xml"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>org.springframework.boot<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>spring-boot-starter-web<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>mysql<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>mysql-connector-java<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>org.mybatis.spring.boot<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>mybatis-spring-boot-starter<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>version</span><span class="token punctuation">&gt;</span></span>2.1.3<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>version</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>org.springframework.boot<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>spring-boot-starter-jdbc<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>
 
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>org.springframework.boot<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>spring-boot-starter-data-redis<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>2、application.yml</p><div class="language-yaml line-numbers-mode" data-ext="yml"><pre class="language-yaml"><code><span class="token key atrule">server</span><span class="token punctuation">:</span>
  <span class="token key atrule">port</span><span class="token punctuation">:</span> <span class="token number">8080</span>
<span class="token key atrule">spring</span><span class="token punctuation">:</span>
  <span class="token key atrule">application</span><span class="token punctuation">:</span>
    <span class="token key atrule">name</span><span class="token punctuation">:</span> distribute<span class="token punctuation">-</span>redis

  <span class="token key atrule">datasource</span><span class="token punctuation">:</span>
    <span class="token key atrule">driver-class-name</span><span class="token punctuation">:</span> com.mysql.jdbc.Driver
    <span class="token key atrule">username</span><span class="token punctuation">:</span> root
    <span class="token key atrule">password</span><span class="token punctuation">:</span> root
    <span class="token key atrule">url</span><span class="token punctuation">:</span> jdbc<span class="token punctuation">:</span>mysql<span class="token punctuation">:</span>//localhost<span class="token punctuation">:</span>3306/k15<span class="token punctuation">?</span>serverTimezone=UTC

  <span class="token key atrule">redis</span><span class="token punctuation">:</span>
    <span class="token key atrule">host</span><span class="token punctuation">:</span> 127.0.0.1
    <span class="token key atrule">port</span><span class="token punctuation">:</span> <span class="token number">6379</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>3、controller</p><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token annotation punctuation">@RequestMapping</span><span class="token punctuation">(</span><span class="token string">&quot;/add/department&quot;</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">addDepartment</span><span class="token punctuation">(</span><span class="token class-name">AddDepartmentCommand</span> command<span class="token punctuation">)</span><span class="token punctuation">{</span>
    command<span class="token punctuation">.</span><span class="token function">execute</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> <span class="token string">&quot;success&quot;</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token annotation punctuation">@RequestMapping</span><span class="token punctuation">(</span><span class="token string">&quot;/update/department&quot;</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">updateDepartment</span><span class="token punctuation">(</span><span class="token class-name">UpdateDepartmentCommand</span> command<span class="token punctuation">)</span><span class="token punctuation">{</span>

    command<span class="token punctuation">.</span><span class="token function">execute</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> <span class="token string">&quot;success&quot;</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token annotation punctuation">@RequestMapping</span><span class="token punctuation">(</span><span class="token string">&quot;/department/{id}&quot;</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token class-name">Department</span> <span class="token function">getDepartmentById</span><span class="token punctuation">(</span><span class="token annotation punctuation">@PathVariable</span>  <span class="token class-name">Integer</span> id<span class="token punctuation">)</span><span class="token punctuation">{</span>

    <span class="token class-name">DepartmentQueryCommand</span> command <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">DepartmentQueryCommand</span><span class="token punctuation">(</span>id<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">Department</span> department <span class="token operator">=</span> command<span class="token punctuation">.</span><span class="token function">execute</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> department<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>查询部分</p><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token annotation punctuation">@Slf4j</span>
<span class="token annotation punctuation">@Data</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">DepartmentQueryCommand</span> <span class="token punctuation">{</span>

    <span class="token keyword">private</span> <span class="token class-name">Integer</span> id<span class="token punctuation">;</span>

    <span class="token keyword">private</span> <span class="token class-name">DepartmentQueryCommandHandler</span> departmentQueryCommandHandler<span class="token punctuation">;</span>

    <span class="token keyword">public</span> <span class="token class-name">DepartmentQueryCommand</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
        departmentQueryCommandHandler <span class="token operator">=</span> <span class="token class-name">ApplicationContextHolder</span>
                <span class="token punctuation">.</span><span class="token function">getApplicationContext</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
                <span class="token punctuation">.</span><span class="token function">getBean</span><span class="token punctuation">(</span><span class="token class-name">DepartmentQueryCommandHandler</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">public</span> <span class="token class-name">DepartmentQueryCommand</span><span class="token punctuation">(</span><span class="token class-name">Integer</span> id<span class="token punctuation">)</span><span class="token punctuation">{</span>
        <span class="token keyword">this</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
       <span class="token keyword">this</span><span class="token punctuation">.</span>id <span class="token operator">=</span> id<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">public</span> <span class="token class-name">Department</span> <span class="token function">execute</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
        <span class="token keyword">return</span> departmentQueryCommandHandler<span class="token punctuation">.</span><span class="token function">action</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token annotation punctuation">@Component</span>
<span class="token annotation punctuation">@Slf4j</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">DepartmentQueryCommandHandler</span> <span class="token punctuation">{</span>

    <span class="token annotation punctuation">@Autowired</span>
    <span class="token keyword">private</span> <span class="token class-name">DepartmentDao</span> departmentDao<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Autowired</span>
    <span class="token keyword">private</span> <span class="token class-name">DepartmentRedisDao</span> departmentRedisDao<span class="token punctuation">;</span>

    <span class="token keyword">public</span> <span class="token class-name">Department</span> <span class="token function">action</span><span class="token punctuation">(</span><span class="token class-name">DepartmentQueryCommand</span> command<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">Department</span> department <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Department</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        department<span class="token punctuation">.</span><span class="token function">setId</span><span class="token punctuation">(</span>command<span class="token punctuation">.</span><span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">Department</span> temp <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
        <span class="token keyword">try</span> <span class="token punctuation">{</span>
            temp <span class="token operator">=</span> departmentRedisDao<span class="token punctuation">.</span><span class="token function">findById</span><span class="token punctuation">(</span>department<span class="token punctuation">.</span><span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            log<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">&quot;从缓存redis查&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>temp <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                temp <span class="token operator">=</span> departmentDao<span class="token punctuation">.</span><span class="token function">selectByPrimaryKey</span><span class="token punctuation">(</span>department<span class="token punctuation">.</span><span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                departmentRedisDao<span class="token punctuation">.</span><span class="token function">save</span><span class="token punctuation">(</span>temp<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> ex<span class="token punctuation">)</span> <span class="token punctuation">{</span>

        <span class="token punctuation">}</span>
        <span class="token keyword">return</span> temp<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>更新部分</p><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token annotation punctuation">@Slf4j</span>
<span class="token annotation punctuation">@Data</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">UpdateDepartmentCommand</span> <span class="token punctuation">{</span>

    <span class="token keyword">private</span> <span class="token class-name">Integer</span> id<span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> name<span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> location<span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token class-name">Integer</span> version<span class="token punctuation">;</span>

    <span class="token keyword">private</span> <span class="token class-name">UpdateDepartmentCommandHandler</span> updateDepartmentCommandHandler<span class="token punctuation">;</span>

    <span class="token keyword">public</span> <span class="token class-name">UpdateDepartmentCommand</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
        updateDepartmentCommandHandler <span class="token operator">=</span> <span class="token class-name">ApplicationContextHolder</span>
                    <span class="token punctuation">.</span><span class="token function">getApplicationContext</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
                    <span class="token punctuation">.</span><span class="token function">getBean</span><span class="token punctuation">(</span><span class="token class-name">UpdateDepartmentCommandHandler</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">execute</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
        updateDepartmentCommandHandler<span class="token punctuation">.</span><span class="token function">action</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token annotation punctuation">@Component</span>
<span class="token annotation punctuation">@Slf4j</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">UpdateDepartmentCommandHandler</span> <span class="token punctuation">{</span>
    <span class="token annotation punctuation">@Autowired</span>
    <span class="token keyword">private</span> <span class="token class-name">DepartmentDao</span> departmentDao<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Autowired</span>
    <span class="token keyword">private</span> <span class="token class-name">DepartmentRedisDao</span> departmentRedisDao<span class="token punctuation">;</span>

    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">action</span><span class="token punctuation">(</span><span class="token class-name">UpdateDepartmentCommand</span> command<span class="token punctuation">)</span><span class="token punctuation">{</span>
        <span class="token class-name">Department</span> department <span class="token operator">=</span> departmentDao<span class="token punctuation">.</span><span class="token function">selectByPrimaryKey</span><span class="token punctuation">(</span>command<span class="token punctuation">.</span><span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">//此处不进行非空判断</span>
        <span class="token class-name">BeanUtils</span><span class="token punctuation">.</span><span class="token function">copyProperties</span><span class="token punctuation">(</span>command<span class="token punctuation">,</span>department<span class="token punctuation">)</span><span class="token punctuation">;</span>
        departmentDao<span class="token punctuation">.</span><span class="token function">updateByPrimaryKey</span><span class="token punctuation">(</span>department<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">//删除redis操作</span>
        departmentRedisDao<span class="token punctuation">.</span><span class="token function">delete</span><span class="token punctuation">(</span>department<span class="token punctuation">)</span><span class="token punctuation">;</span>
        log<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">&quot;从redis删除成功&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>添加部分</p><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token annotation punctuation">@Slf4j</span>
<span class="token annotation punctuation">@Data</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">AddDepartmentCommand</span> <span class="token punctuation">{</span>

    <span class="token keyword">private</span> <span class="token class-name">Integer</span> id<span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> name<span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> location<span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token class-name">Integer</span> version<span class="token punctuation">;</span>

    <span class="token keyword">private</span> <span class="token class-name">AddDepartmentCommandHandler</span> addDepartmentCommandHandler<span class="token punctuation">;</span>

    <span class="token keyword">public</span> <span class="token class-name">AddDepartmentCommand</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>addDepartmentCommandHandler <span class="token operator">=</span>
                <span class="token class-name">ApplicationContextHolder</span><span class="token punctuation">.</span><span class="token function">getApplicationContext</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
                        <span class="token punctuation">.</span><span class="token function">getBean</span><span class="token punctuation">(</span><span class="token class-name">AddDepartmentCommandHandler</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>


    <span class="token keyword">public</span> <span class="token keyword">int</span> <span class="token function">execute</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
       <span class="token keyword">return</span>  addDepartmentCommandHandler<span class="token punctuation">.</span><span class="token function">action</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token annotation punctuation">@Slf4j</span>
<span class="token annotation punctuation">@Component</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">AddDepartmentCommandHandler</span> <span class="token punctuation">{</span>

    <span class="token annotation punctuation">@Autowired</span>
    <span class="token keyword">private</span> <span class="token class-name">DepartmentDao</span> departmentDao <span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Autowired</span>
    <span class="token keyword">private</span> <span class="token class-name">DepartmentRedisDao</span> departmentRedisDao<span class="token punctuation">;</span>

    <span class="token keyword">public</span> <span class="token keyword">int</span>  <span class="token function">action</span><span class="token punctuation">(</span><span class="token class-name">AddDepartmentCommand</span> command<span class="token punctuation">)</span><span class="token punctuation">{</span>
        <span class="token class-name">Department</span> department <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Department</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        department<span class="token punctuation">.</span><span class="token function">setVersion</span><span class="token punctuation">(</span>command<span class="token punctuation">.</span><span class="token function">getVersion</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        department<span class="token punctuation">.</span><span class="token function">setName</span><span class="token punctuation">(</span>command<span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        department<span class="token punctuation">.</span><span class="token function">setLocation</span><span class="token punctuation">(</span>command<span class="token punctuation">.</span><span class="token function">getLocation</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">int</span> flag  <span class="token operator">=</span> departmentDao<span class="token punctuation">.</span><span class="token function">insertSelective</span><span class="token punctuation">(</span>department<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">//往redis添加一条数据</span>
        departmentRedisDao<span class="token punctuation">.</span><span class="token function">save</span><span class="token punctuation">(</span>department<span class="token punctuation">)</span><span class="token punctuation">;</span>
        log<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">&quot;保存到redis成功&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> flag<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>dao层</p><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token annotation punctuation">@Component</span>
<span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">DepartmentDao</span>  <span class="token keyword">extends</span> <span class="token class-name">Mapper</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Department</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">{</span>

    <span class="token annotation punctuation">@Update</span><span class="token punctuation">(</span><span class="token string">&quot;update department set name = #{name},version = #{version}+1 where id = #{id} and version = #{version}&quot;</span><span class="token punctuation">)</span>
    <span class="token keyword">public</span> <span class="token keyword">int</span> <span class="token function">updateDepartment</span><span class="token punctuation">(</span><span class="token class-name">Department</span> department<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token annotation punctuation">@Component</span>
<span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">DepartmentRedisDao</span> <span class="token keyword">extends</span> <span class="token class-name">CrudRepository</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Department</span><span class="token punctuation">,</span><span class="token class-name">Integer</span><span class="token punctuation">&gt;</span></span> <span class="token punctuation">{</span>

<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="cap-方案的改进" tabindex="-1"><a class="header-anchor" href="#cap-方案的改进" aria-hidden="true">#</a> CAP 方案的改进</h3><h4 id="延期删除" tabindex="-1"><a class="header-anchor" href="#延期删除" aria-hidden="true">#</a> 延期删除</h4><p>将写操作的『删除 Redis』操作改为异步的延迟删除。例如：更新完数据库，1 秒钟之后再删除缓存，这种情况下，读写并发造成的数据不一致问题最多也就存在 1 秒</p><blockquote><p>这个改进方案的问题在于：你要延迟多久？延迟的时间短了没有解决读写并发问题；延迟的时间越长不一致隐患就越大。</p></blockquote><p>延期的好处：</p><p>正常情况下，A线程读操作，B线程写操作，假如说B先更新数据库，然后删除redis缓存，在B删除redis缓存期间，A没有读操作，然后等B删除redis完成，A再查，发现缓存没有，查数据库，然后再更新缓存，这是正常的。</p><p>如果是A先读的呢？A先找redis缓存，发现没有，然后查数据库，完了之后，当它将数据库数据写到redis缓存之前，这个时候B更新了数据库，然后删除了缓存，然后A在更新redis缓存，那么redis缓存就是旧数据库了。所以这个时候延期删除的话，目的就是等到A放到缓存之后再删除。那么延期多久呢？这也是个问题</p><h4 id="借助消息队列-将删存缓存的工作委托给第三方" tabindex="-1"><a class="header-anchor" href="#借助消息队列-将删存缓存的工作委托给第三方" aria-hidden="true">#</a> 借助消息队列，将删存缓存的工作委托给第三方</h4><ul><li>读数据的人，先查redis缓存，发现没有数据时，它去查数据库拿到结果，但是把这个结果放到redis缓存不再由它自己来完成，而是发消息给消息队列，队列监听到数据，然后将数据存redis，不再由他自己来刷新缓存，而是由『别人』来刷新；</li><li>写数据的人，在更新完数据库之后，同样发送消息给消息队列，表示要删除缓存，队列存该消息，有监听器接收到该消息，去执行删除缓存操作，不再由他自己来删除缓存，而是由『别人』来删除；</li></ul><p>好处：<strong>读和写操作，送到队列这是有先后的，将并行化产生的问题，由串行化顺序执行</strong></p><p>坏处：代价很大，一旦消息队列宕机，整个过程结束</p><p><img src="https://apaiimages.oss-cn-guangzhou.aliyuncs.com/MD/image-20211023130205539.png" alt="image-20211023130205539"></p><blockquote><p>说明：</p><p>这些改建方案不一定用得上。原因在于：</p><ol><li>有数据不一致的窗口期，这是可接受的。</li><li>改进方案虽然改进了问题，但是同时带来了复杂性</li></ol></blockquote><h2 id="redis-redisson-锁-分布式锁" tabindex="-1"><a class="header-anchor" href="#redis-redisson-锁-分布式锁" aria-hidden="true">#</a> Redis/Redisson 锁 | 分布式锁</h2><h3 id="分布式锁使用场景" tabindex="-1"><a class="header-anchor" href="#分布式锁使用场景" aria-hidden="true">#</a> 分布式锁使用场景</h3><p>随着互联网技术的不断发展，数据量的不断增加，业务逻辑日趋复杂，在这种背景下，传统的集中式系统已经无法满足我们的业务需求，分布式系统被应用在更多的场景，而在分布式系统中访问共享资源就需要一种互斥机制，来防止彼此之间的互相干扰，以保证一致性，在这种情况下，我们就需要用到分布式锁</p><p>首先我们先来看一个小例子：</p><p>假设某商城有一个商品库存剩10个，用户A想要买6个，用户B想要买5个，在理想状态下，用户A先买走了6了，库存减少6个还剩4个，此时用户B应该无法购买5个，给出数量不足的提示；而在真实情况下，用户A和B同时获取到商品剩10个，A买走6个，在A更新库存之前，B又买走了5个，此时B更新库存，商品还剩5个，这就是典型的电商“秒杀”活动。</p><p>从上述例子不难看出，在高并发情况下，如果不做处理将会出现各种不可预知的后果。那么在这种高并发多线程的情况下，解决问题最有效最普遍的方法就是给共享资源或对共享资源的操作加一把锁，来保证对资源的访问互斥。在Java JDK已经为我们提供了这样的锁，利用ReentrantLock或者synchronized，即可达到资源互斥访问的目的。但是在分布式系统中，由于分布式系统的分布性，即多线程和多进程并且分布在不同机器中，<strong>也就是说一个服务可以同时启动多个实例，不同用户访问不同的实例</strong>，那么这两种锁将失去原有锁的效果，需要我们自己实现分布式锁——分布式锁。</p><p>一般我们使用分布式锁有两个场景：</p><ul><li><strong>效率</strong>：使用分布式锁可以避免不同节点重复相同的工作，这些工作会浪费资源。比如用户付了钱之后有可能不同节点会发出多封短信。</li><li><strong>正确性</strong>：加分布式锁同样可以避免破坏正确性的发生，如果两个节点在同一条数据上面操作，比如多个节点机器对同一个订单操作不同的流程有可能会导致该笔订单最后状态出现错误，造成损失。</li></ul><p>Redis 因为其性能好，实现起来分布式锁简单，所以让很多人都对基于 Redis 实现的分布式锁十分青睐。</p><blockquote><p>提示</p><p>除了能使用 Redis 实现分布式锁之外，Zookeeper 也能实现分布式锁。但是项目中不可能仅仅为了实现分布式锁而专门引入 Zookeeper ，所以，除非你的项目体系中本来就有 Zookeeper（来实现其它功能），否则不会单独因为分布式锁而引入它</p></blockquote><h3 id="redis-锁" tabindex="-1"><a class="header-anchor" href="#redis-锁" aria-hidden="true">#</a> Redis 锁</h3><h4 id="setnx-命令" tabindex="-1"><a class="header-anchor" href="#setnx-命令" aria-hidden="true">#</a> SETNX 命令</h4><p>早期，SETNX 是独立于 SET 命令之外的另一条命令。它的意思是 <strong>SET</strong> if <strong>N</strong>ot e<strong>X</strong>ists，即，在键值对不存在的时候才能设值成功。</p><p>注意:SETNX 命令的价值在于：它将 <code>判断</code> 和 <code>设值</code> 两个操作合二为一，从而避免了 <code>查查改改</code> 的情况的出现。</p><p>后来，在 Redis 2013 年推出的 2.6.12 版本中，Redis 为 SET 命令官方提供了 NX 选项，使得 SET 命令也能实现 SETNX 命令的功能。其语法如下：</p><div class="language-bash line-numbers-mode" data-ext="sh"><pre class="language-bash"><code>SET <span class="token operator">&lt;</span>key<span class="token operator">&gt;</span> <span class="token operator">&lt;</span>value<span class="token operator">&gt;</span> <span class="token punctuation">[</span>EX seconds<span class="token punctuation">]</span> <span class="token punctuation">[</span>PX milliseconds<span class="token punctuation">]</span> <span class="token punctuation">[</span>NX <span class="token operator">|</span> XX<span class="token punctuation">]</span>
<span class="token comment">## SET &lt;键&gt; &lt;内容&gt; [过期时间] // 详情见 redis 命令</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div></div></div><p><strong>EX</strong> 值的是 <code>key</code> 的存活时间，单位为秒。<strong>PX</strong> 与 <strong>EX</strong> 作用一样，唯一的不同就是后者的单位是微秒（使用较少）。</p><p><strong>NX</strong> 和 <strong>XX</strong> 作用是相反的。<strong>NX</strong> 表示只有当 key『<strong>不存在时</strong>』才会设置其值；<strong>XX</strong> 表示当 <code>key</code> 存在时才设置 <code>key</code> 的值。</p><p>在 “升级” 了 SET 命令之后，Redis 官方说：“由于 SET 命令选项可以替换 SETNX，SETEX，因此在 Redis 的将来版本中，这二个命令可能会被弃用并最终删除”。</p><p>所以，现在我们口头所说的 SETNX 命令，并非单指 SETNX 命令，而是包括带 NX 选项的 SET 命令（甚至以后就没有 SETNX 命令了）</p><h4 id="setnx-的使用" tabindex="-1"><a class="header-anchor" href="#setnx-的使用" aria-hidden="true">#</a> SETNX 的使用</h4><p>在使用 <code>SETNX</code> 操作实现分布式锁功能时，需要注意以下几点：</p><ul><li>这里的『锁』指的是 Redis 中的一个认为约定的键值对。谁能创建这个键值对，就意味着谁拥有这整个『锁』。</li><li>使用 <code>SETNX</code> 命令获取『锁』时，如果操作返回结果是 0（表示 key 已存在，设值失败），则意味着获取『锁』失败（该锁被其它线程先获取），反之，则设值成功，表示获取『锁』成功。 <ul><li>如果这个 <strong>key</strong> 不存在，SETNX 才会设置该 key 的值。此时 Redis 返回 1 。</li><li>如果这个 <strong>key</strong> 存在，SETNX 则不会设置该 key 的值。此时 Redis 返回 0 。</li></ul></li><li>为了防止其它线程获得『锁』之后，有意或无意，长期持有『锁』而不释放（导致其它线程无法获得该『锁』）。因此，需要为 key 设置一个合理的过期时间。</li><li>当成功获得『锁』并成功完成响应操作之后，需要释放『锁』（可以执行 DEL 命令将『锁』删除）。</li></ul><p>在代码层面，与 Setnx 命令对应的接口是 ValueOperations 的 <strong>setIfAbsent</strong> 方法</p><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">com<span class="token punctuation">.</span>api<span class="token punctuation">.</span></span><span class="token class-name">Controller</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>beans<span class="token punctuation">.</span>factory<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">Autowired</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>data<span class="token punctuation">.</span>redis<span class="token punctuation">.</span>core<span class="token punctuation">.</span></span><span class="token class-name">StringRedisTemplate</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>data<span class="token punctuation">.</span>redis<span class="token punctuation">.</span>core<span class="token punctuation">.</span></span><span class="token class-name">ValueOperations</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>web<span class="token punctuation">.</span>bind<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">GetMapping</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>web<span class="token punctuation">.</span>bind<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">RestController</span></span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token import"><span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span>concurrent<span class="token punctuation">.</span></span><span class="token class-name">TimeUnit</span></span><span class="token punctuation">;</span>

<span class="token annotation punctuation">@RestController</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">TestController</span> <span class="token punctuation">{</span>

    <span class="token annotation punctuation">@Autowired</span>
    <span class="token keyword">private</span> <span class="token class-name">StringRedisTemplate</span> redisTemplate<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@GetMapping</span><span class="token punctuation">(</span><span class="token string">&quot;setntx&quot;</span><span class="token punctuation">)</span>
    <span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">text</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">InterruptedException</span> <span class="token punctuation">{</span>
        <span class="token comment">// 获取 SETNX 命令实例</span>
        <span class="token class-name">ValueOperations</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">String</span><span class="token punctuation">&gt;</span></span> ops <span class="token operator">=</span> redisTemplate<span class="token punctuation">.</span><span class="token function">opsForValue</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 根据键存入内容 并设置该key键的过期的时间 单位为秒 | 成功存入: true 反之:false</span>
        <span class="token keyword">while</span><span class="token punctuation">(</span><span class="token operator">!</span><span class="token class-name">Boolean</span><span class="token punctuation">.</span><span class="token constant">TRUE</span><span class="token punctuation">.</span><span class="token function">equals</span><span class="token punctuation">(</span>ops<span class="token punctuation">.</span><span class="token function">setIfAbsent</span><span class="token punctuation">(</span><span class="token string">&quot;apai&quot;</span><span class="token punctuation">,</span><span class="token string">&quot;bye&quot;</span><span class="token punctuation">,</span> <span class="token number">13000</span><span class="token punctuation">,</span> <span class="token class-name">TimeUnit</span><span class="token punctuation">.</span><span class="token constant">MILLISECONDS</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
            <span class="token comment">//延迟1秒执行，继续取set  看看是否成功</span>
            <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">currentThread</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">+</span><span class="token string">&quot;:获取锁失败&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token class-name">TimeUnit</span><span class="token punctuation">.</span><span class="token constant">MILLISECONDS</span><span class="token punctuation">.</span><span class="token function">sleep</span><span class="token punctuation">(</span><span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">try</span> <span class="token punctuation">{</span>
            <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">currentThread</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">+</span><span class="token string">&quot;:处理业务&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">sleep</span><span class="token punctuation">(</span><span class="token number">10000</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span> <span class="token keyword">catch</span><span class="token punctuation">(</span><span class="token class-name">Exception</span> exception<span class="token punctuation">)</span><span class="token punctuation">{</span>
        <span class="token punctuation">}</span><span class="token keyword">finally</span> <span class="token punctuation">{</span>
            <span class="token comment">// 删除该key键和内容</span>
            redisTemplate<span class="token punctuation">.</span><span class="token function">delete</span><span class="token punctuation">(</span><span class="token string">&quot;apai&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">return</span> <span class="token string">&quot;月亮如此凄美&quot;</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

<span class="token punctuation">}</span>

</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>开启两个不同的浏览器发请求测试</p><p>上面的代码逻辑有 3 个小问题：</p><ol><li><p>上锁时，设置的超时自动删除时长（3 秒），设置多长合适？万一设置短了怎么办?</p><p>如果设置短了，在业务逻辑执行完之前时间到期，那么 Redis 自动就把键值对给删除了，即，把锁给释放了，这不符合逻辑。</p></li><li><p>解锁时，<code>查 - 删</code> 操作是 2 个操作，由两个命令完成，非原子性。</p></li><li><p>redis底层执行这个setnx不是一个原子操作，而是有两步操作完成的，首先set hello world，然后第二步设置key的过期时间： expire hello 3，那么如果执行完第一步刚好redis宕机了，此时key一直保存到redis。永远也无法删除了。</p></li></ol><p>当然，上述两个问题我们都能解决，不过有人（ Redisson ）帮我们把这些事情做好了</p><h4 id="redisson-如何解决问题" tabindex="-1"><a class="header-anchor" href="#redisson-如何解决问题" aria-hidden="true">#</a> Redisson 如何解决问题</h4><ul><li><p>Redisson 解决 “过期自动删除时长” 问题的思路和方案</p><p>Redisson 中客户端一旦加锁成功，就会启动一个后台线程（惯例称之为 watch dog 看门狗）。watch dog 线程默认会每隔 10 秒检查一下，如果锁 key 还存在，那么它会不断的延长锁 key 的生存时间，直到你的代码中去删除锁 key 。</p></li><li><p>Redisson 解决setnx和 解锁的<strong>非原子性</strong> 问题的思路和方案</p><p>Redisson 的上锁和解锁操作都是通过 Lua 脚本实现的。Redis 中 执行 Lua 脚本能保证原子性，整段 Lua 脚本的执行是原子性的，在其执行期间 Redis 不会再去执行其它命令</p></li></ul><h3 id="redisson-锁" tabindex="-1"><a class="header-anchor" href="#redisson-锁" aria-hidden="true">#</a> Redisson 锁</h3><p><strong>防坑指南</strong></p><ul><li>持有锁的线程可以反复上锁，而不会失败，或阻塞等待；锁的非持有者上锁时，则会失败，或需要等待</li><li>指定了超时自动删除时间，而且如果你的业务执行时间过长，超过了key的过期时间， 而你在执行完业务之后也去删除这个key，就会报错</li><li>一旦 设置了key的过期时间 则导致watch dog失效从而不会进行自动续期</li></ul><p><strong>Redisson API</strong></p><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token comment">// 注入Redisson配置对象实例 前提需创建配置类</span>
<span class="token annotation punctuation">@Autowired</span>
<span class="token keyword">private</span> <span class="token class-name">RedissonClient</span> redissonClient<span class="token punctuation">;</span>

<span class="token comment">// 获取一把锁对象，此时还没有加锁</span>
<span class="token class-name">RLock</span> rLock <span class="token operator">=</span> redissonClient<span class="token punctuation">.</span><span class="token function">getLock</span><span class="token punctuation">(</span><span class="token string">&quot;key&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 加锁，其实就是设置一个key-value   默认加的锁都是30s  </span>
rLock<span class="token punctuation">.</span><span class="token function">lock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 3秒钟 自动解锁 即过期 | 注意: 一旦设置时间 就不会自动续期</span>
rLock<span class="token punctuation">.</span><span class="token function">lock</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token class-name">TimeUnit</span><span class="token punctuation">.</span><span class="token constant">SECONDS</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 删掉一个key</span>
rLock<span class="token punctuation">.</span><span class="token function">unlock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>  

<span class="token comment">// 拿不到就立刻返回</span>
<span class="token keyword">boolean</span> b <span class="token operator">=</span> rLock<span class="token punctuation">.</span><span class="token function">tryLock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 拿不到最多等 1 秒。1 秒内始终拿不到，就返回</span>
<span class="token keyword">boolean</span> b1 <span class="token operator">=</span> rLock<span class="token punctuation">.</span><span class="token function">tryLock</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token class-name">TimeUnit</span><span class="token punctuation">.</span><span class="token constant">SECONDS</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 尝试在1s内去拿锁，拿不到就返回false，拿到了10s自动释放这个锁 | 一旦设置时间 就不会自动续期</span>
<span class="token keyword">boolean</span> b2 <span class="token operator">=</span> rLock<span class="token punctuation">.</span><span class="token function">tryLock</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">,</span> <span class="token class-name">TimeUnit</span><span class="token punctuation">.</span><span class="token constant">SECONDS</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>1、引入 redisson 包</p><div class="language-xml line-numbers-mode" data-ext="xml"><pre class="language-xml"><code><span class="token comment">&lt;!-- Redisson 分布式锁 --&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>org.redisson<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>redisson<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>version</span><span class="token punctuation">&gt;</span></span>3.15.6<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>version</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>2、配置 Redisson Client</p><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">com<span class="token punctuation">.</span>api<span class="token punctuation">.</span>config</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>redisson<span class="token punctuation">.</span></span><span class="token class-name">Redisson</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>redisson<span class="token punctuation">.</span>api<span class="token punctuation">.</span></span><span class="token class-name">RedissonClient</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>redisson<span class="token punctuation">.</span>config<span class="token punctuation">.</span></span><span class="token class-name">Config</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>context<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">Bean</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>context<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">Configuration</span></span><span class="token punctuation">;</span>

<span class="token annotation punctuation">@Configuration</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">RedissonConfig</span> <span class="token punctuation">{</span>
    <span class="token annotation punctuation">@Bean</span>
    <span class="token keyword">public</span> <span class="token class-name">RedissonClient</span> <span class="token function">getRedissonClient</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
        <span class="token class-name">Config</span> config <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Config</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">//config.setLockWatchdogTimeout();</span>
        <span class="token comment">// 注意配置 redis 路径</span>
        config<span class="token punctuation">.</span><span class="token function">useSingleServer</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">setAddress</span><span class="token punctuation">(</span><span class="token string">&quot;redis://192.168.174.133:6379&quot;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">setKeepAlive</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> <span class="token class-name">Redisson</span><span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span>config<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>3、测试</p><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">com<span class="token punctuation">.</span>api<span class="token punctuation">.</span>controller</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>redisson<span class="token punctuation">.</span>api<span class="token punctuation">.</span></span><span class="token class-name">RLock</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>redisson<span class="token punctuation">.</span>api<span class="token punctuation">.</span></span><span class="token class-name">RedissonClient</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>beans<span class="token punctuation">.</span>factory<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">Autowired</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>data<span class="token punctuation">.</span>redis<span class="token punctuation">.</span>core<span class="token punctuation">.</span></span><span class="token class-name">ValueOperations</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>web<span class="token punctuation">.</span>bind<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">GetMapping</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>web<span class="token punctuation">.</span>bind<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">RestController</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span>concurrent<span class="token punctuation">.</span></span><span class="token class-name">TimeUnit</span></span><span class="token punctuation">;</span>

<span class="token annotation punctuation">@RestController</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">TestController</span> <span class="token punctuation">{</span>

    <span class="token annotation punctuation">@Autowired</span>
    <span class="token keyword">private</span> <span class="token class-name">RedissonClient</span> redissonClient<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@GetMapping</span><span class="token punctuation">(</span><span class="token string">&quot;/hello&quot;</span><span class="token punctuation">)</span>
    <span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">hello1</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">InterruptedException</span> <span class="token punctuation">{</span>
        <span class="token comment">// 获取一把锁对象，此时还没有加锁</span>
        <span class="token class-name">RLock</span> rLock <span class="token operator">=</span> redissonClient<span class="token punctuation">.</span><span class="token function">getLock</span><span class="token punctuation">(</span><span class="token string">&quot;hello&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">try</span> <span class="token punctuation">{</span>
            <span class="token comment">// 加锁，其实就是设置一个key-value   默认加的锁都是30s</span>
            rLock<span class="token punctuation">.</span><span class="token function">lock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">sleep</span><span class="token punctuation">(</span><span class="token number">5000</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">currentThread</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">+</span><span class="token string">&quot;:处理业务&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span> <span class="token keyword">catch</span><span class="token punctuation">(</span><span class="token class-name">Exception</span> exception<span class="token punctuation">)</span><span class="token punctuation">{</span>
        <span class="token punctuation">}</span><span class="token keyword">finally</span> <span class="token punctuation">{</span>
            <span class="token comment">// 删掉一个key</span>
            rLock<span class="token punctuation">.</span><span class="token function">unlock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">return</span> <span class="token string">&quot;ok&quot;</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>测试2：</p><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token annotation punctuation">@Test</span>
<span class="token keyword">void</span> <span class="token function">contextLoads</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> <span class="token number">5</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">final</span> <span class="token keyword">long</span> seconds  <span class="token operator">=</span> i<span class="token punctuation">;</span>
        <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-&gt;</span> <span class="token punctuation">{</span>
            <span class="token class-name">RLock</span> hello <span class="token operator">=</span> redissonClient<span class="token punctuation">.</span><span class="token function">getLock</span><span class="token punctuation">(</span><span class="token string">&quot;hello&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            hello<span class="token punctuation">.</span><span class="token function">lock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;lock success。准备睡 &quot;</span> <span class="token operator">+</span> seconds <span class="token operator">+</span> <span class="token string">&quot; 秒，再起来释放锁&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">try</span> <span class="token punctuation">{</span>
                <span class="token class-name">TimeUnit</span><span class="token punctuation">.</span><span class="token constant">SECONDS</span><span class="token punctuation">.</span><span class="token function">sleep</span><span class="token punctuation">(</span>seconds<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">InterruptedException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span><span class="token keyword">finally</span> <span class="token punctuation">{</span>
                hello<span class="token punctuation">.</span><span class="token function">unlock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">while</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="redisson分析" tabindex="-1"><a class="header-anchor" href="#redisson分析" aria-hidden="true">#</a> Redisson分析</h4><p>1、你通过 RedissonClient 拿到的锁都是 “<strong>可重入锁</strong>” 。这里的 “可重入” 的意思是：持有锁的线程可以反复上锁，而不会失败，或阻塞等待；锁的非持有者上锁时，则会失败，或需要等待。当然，如果你对一个锁反复上锁，那么逻辑上，你应该对它执行同样多次的解锁操作</p><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token annotation punctuation">@Autowired</span>
<span class="token keyword">private</span> <span class="token class-name">RedissonClient</span> redissonClient<span class="token punctuation">;</span>
<span class="token annotation punctuation">@Test</span>
<span class="token keyword">void</span> <span class="token function">contextLoads</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token class-name">RLock</span> rLock <span class="token operator">=</span> redissonClient<span class="token punctuation">.</span><span class="token function">getLock</span><span class="token punctuation">(</span><span class="token string">&quot;hello&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    rLock<span class="token punctuation">.</span><span class="token function">lock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;lock success!&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    rLock<span class="token punctuation">.</span><span class="token function">lock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;lock success!&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    rLock<span class="token punctuation">.</span><span class="token function">lock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;lock success!&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    rLock<span class="token punctuation">.</span><span class="token function">unlock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    rLock<span class="token punctuation">.</span><span class="token function">unlock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    rLock<span class="token punctuation">.</span><span class="token function">unlock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>使用 lock( )上锁时由于你没有指定过期删除时间，所以，逻辑上只有当你调用 unlock( )之后，Redis 中代表这个锁的简直对才会被删除。当然你也可以在 lock 时指定超时自动解锁时间：</p><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code>rLock<span class="token punctuation">.</span><span class="token function">lock</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token class-name">TimeUnit</span><span class="token punctuation">.</span><span class="token constant">SECONDS</span><span class="token punctuation">)</span><span class="token punctuation">;</span>  <span class="token comment">//3秒钟 自动解锁</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>这种情况下，如果你有意或无意没有调用 unlock 进行解锁，那么 3秒后，Redis 也会自动删除代表这个锁的键值对</p><p>2、当两个不同的线程对同一个锁进行 lock 时，第二个线程的上锁操作会失败。而上锁失败的默认行为是阻塞等待，直到前一个线程释放掉锁。这种情况下，如果你不愿意等待，那么你可以调用 <code>tryLock()</code> 方法上锁。tryLock 上锁会立刻（或最多等一段时间）返回，而不会一直等（直到所得持有线程释放）。</p><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token comment">// 拿不到就立刻返回</span>
hello<span class="token punctuation">.</span><span class="token function">tryLock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 拿不到最多等 1 秒。1 秒内始终拿不到，就返回</span>
hello<span class="token punctuation">.</span><span class="token function">tryLock</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token class-name">TimeUnit</span><span class="token punctuation">.</span><span class="token constant">SECONDS</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 尝试在1s内去拿锁，拿不到就返回false，拿到了10s自动释放这个锁</span>
hello<span class="token punctuation">.</span><span class="token function">tryLock</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">,</span> <span class="token class-name">TimeUnit</span><span class="token punctuation">.</span><span class="token constant">SECONDS</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>3、Redisson 在上锁时，向 Redis 中添加的键值对时，通过hset设置k-v的，其中键就是hello，当然你也可以是其它的值，那么这个值里面的键是redisson内部帮我们生成的UUID +“：” +thread-id 拼接而成的字符串；值是这个锁的上锁次数，默认是1</p><p>Redisson 如何保证线程间的互斥以及锁的重入（反复上锁）？</p><p>因为代表这锁的键值对的键中含有线程 ID ，因此，当你执行上锁操作时，Redisson 会判断你是否是锁的持有者，即，当前线程的 ID 是否和键值对中的线程 ID 一样。</p><p>如果当前执行 lock 的线程 ID 和之前执行 lock 成功的线程的 ID 不一致，则意味着是 “第二个人在申请锁” ，那么就 lock 失败；如果 ID 是一样的，那么就是 “同一个” 在反复 lock，那么就累加锁的上锁次数，即实现了重入。</p><h4 id="watch-dog-自动延期机制" tabindex="-1"><a class="header-anchor" href="#watch-dog-自动延期机制" aria-hidden="true">#</a> watch dog 自动延期机制</h4><p>如果在使用 lock/tryLock 方法时，你<strong>指定了超时自动删除时间，如：hello.tryLock(10, TimeUnit.SECONDS);Redis 会自动10s后将当前线程锁的键值对给删除掉，不会自动续期</strong>，而且如果你的业务执行时间过长，超过了key的过期时间， 而你在执行完业务之后也去删除这个key，就会报错，提示错误为：当前线程不能删除这个key，因为你删的key不是你之前的key，而是另外一个线程给redis重新设置的key。所以设置带过期时间的hello.tryLock(10, TimeUnit.SECONDS)键值对时，时长一定要超过业务执行的时长</p><p>如果，你在使用 lock/tryLock 方法时，没有指定超时自动删除时间，那么，就完全依靠你的手动删除（ unlock 方法 ），那么，这种情况下你会遇到一个问题：如果你有意或无意中忘记了 unlock 释放锁，那么锁背后的键值对将会在 Redis 中长期存在！</p><blockquote><p>一定要注意</p><p>Redisson 看门狗（watch dog）在指定了加锁时间时，是不会对锁时间自动续租的。</p></blockquote><p>在 watch dog 机制中，有一个被 “隐瞒” 的细节：表面上看，你的 lock 方法没有指定锁定时长，但是 Redisson 去 Redis 中添加代表锁的键值对时，它还是添加了自动删除时间。默认 30 秒（可配置）。这意味着，如果，你没有主动 unlock 进行解锁，那么这个代表锁的键值对也会在 30 秒之后被 Redis 自动删除，但是实际上，并没有。这正是因为 Redisson 利用 watch dog 机制对它进行了续期（ 使用 Redis 的 expire 命令重新指定新的过期时间）。也就是内部有一个定时任务，每隔10s会会自动启动定时任务，该任务重新给key续期30s。</p><h4 id="redisson-执行的-lua-脚本" tabindex="-1"><a class="header-anchor" href="#redisson-执行的-lua-脚本" aria-hidden="true">#</a> Redisson 执行的 Lua 脚本</h4><p>1、加锁的LUA脚本</p><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token keyword">if</span> <span class="token punctuation">(</span>redis<span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token char">&#39;exists&#39;</span><span class="token punctuation">,</span> <span class="token constant">KEYS</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> then 
        redis<span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token char">&#39;hset&#39;</span><span class="token punctuation">,</span> <span class="token constant">KEYS</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token constant">ARGV</span><span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
         redis<span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span>&#39;pexpire&#39;<span class="token punctuation">,</span> <span class="token constant">KEYS</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token constant">ARGV</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> 
         <span class="token keyword">return</span> nil<span class="token punctuation">;</span>
    end<span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>redis<span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span>&#39;hexists&#39;<span class="token punctuation">,</span> <span class="token constant">KEYS</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token constant">ARGV</span><span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">1</span><span class="token punctuation">)</span> then
        redis<span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span>&#39;hincrby&#39;<span class="token punctuation">,</span> <span class="token constant">KEYS</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token constant">ARGV</span><span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        redis<span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span>&#39;pexpire&#39;<span class="token punctuation">,</span> <span class="token constant">KEYS</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token constant">ARGV</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> 
        <span class="token keyword">return</span> nil<span class="token punctuation">;</span>
     end<span class="token punctuation">;</span>
<span class="token keyword">return</span> redis<span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token char">&#39;pttl&#39;</span><span class="token punctuation">,</span> <span class="token constant">KEYS</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>2、解锁的LUA脚本</p><div class="language-lua line-numbers-mode" data-ext="lua"><pre class="language-lua"><code><span class="token keyword">if</span> <span class="token punctuation">(</span>redis<span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token string">&#39;exists&#39;</span><span class="token punctuation">,</span> KEYS<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token keyword">then</span>
       redis<span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token string">&#39;publish&#39;</span><span class="token punctuation">,</span> KEYS<span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">,</span> ARGV<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> <span class="token number">1</span><span class="token punctuation">;</span> 
        <span class="token keyword">end</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>redis<span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token string">&#39;hexists&#39;</span><span class="token punctuation">,</span> KEYS<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">,</span> ARGV<span class="token punctuation">[</span><span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token keyword">then</span> 
     <span class="token keyword">return</span> <span class="token keyword">nil</span><span class="token punctuation">;</span>
     <span class="token keyword">end</span><span class="token punctuation">;</span>
<span class="token keyword">local</span> counter <span class="token operator">=</span> redis<span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token string">&#39;hincrby&#39;</span><span class="token punctuation">,</span> KEYS<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">,</span> ARGV<span class="token punctuation">[</span><span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span> 
<span class="token keyword">if</span> <span class="token punctuation">(</span>counter <span class="token operator">&gt;</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token keyword">then</span>
     redis<span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token string">&#39;pexpire&#39;</span><span class="token punctuation">,</span> KEYS<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">,</span> ARGV<span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> 
     <span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span> 
<span class="token keyword">else</span> redis<span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token string">&#39;del&#39;</span><span class="token punctuation">,</span> KEYS<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> 
     redis<span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token string">&#39;publish&#39;</span><span class="token punctuation">,</span> KEYS<span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">,</span> ARGV<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> 
     <span class="token keyword">return</span> <span class="token number">1</span><span class="token punctuation">;</span>
     <span class="token keyword">end</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token keyword">nil</span><span class="token punctuation">;</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div></div></div><footer class="page-meta"><!----><div class="meta-item last-updated"><span class="xicon-container left meta-item-label"><!--[--><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 32 32" class="xicon-icon" style="width:20px;height:20px;font-size:20px;color:inherit;"><path d="M26 4h-4V2h-2v2h-8V2h-2v2H6c-1.1 0-2 .9-2 2v20c0 1.1.9 2 2 2h20c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 22H6V12h20v14zm0-16H6V6h4v2h2V6h8v2h2V6h4v4z" fill="currentColor"></path></svg><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->Last Updated 2023-07-19 09:58:39<!--]--></span></span></div></footer><nav class="page-nav"><p class="hasPrev hasNext inner"><span class="page-nav-item prev"> ← SpringConfig 微服务</span><span class="page-nav-item next">RabbitMQ 消息队列 → </span></p></nav><!----></main><!--]--><div class="page-catalog-container"><h5 class="tip">文章层级目录</h5><ul><!--[--><!--[--><li class="page-catalog-menu-depth_2"><a aria-current="page" href="/docs/Java-develop/Redis.html#redis-内存数据库" class="router-link-active router-link-exact-active link page-catalog-item" aria-label="redis  内存数据库"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->redis  内存数据库<!--]--></span></span><!--[--><!--]--></a></li><!--[--><li class="page-catalog-menu-depth_3"><a aria-current="page" href="/docs/Java-develop/Redis.html#查看默认安装目录" class="router-link-active router-link-exact-active link page-catalog-item" aria-label="查看默认安装目录"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->查看默认安装目录<!--]--></span></span><!--[--><!--]--></a></li><!--]--><!--[--><li class="page-catalog-menu-depth_3"><a aria-current="page" href="/docs/Java-develop/Redis.html#redis-安装配置方法" class="router-link-active router-link-exact-active link page-catalog-item" aria-label="redis -- 安装配置方法"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->redis -- 安装配置方法<!--]--></span></span><!--[--><!--]--></a></li><!--]--><!--]--><!--[--><li class="page-catalog-menu-depth_2"><a aria-current="page" href="/docs/Java-develop/Redis.html#redis-常用指令" class="router-link-active router-link-exact-active link page-catalog-item" aria-label="redis 常用指令"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->redis 常用指令<!--]--></span></span><!--[--><!--]--></a></li><!--[--><li class="page-catalog-menu-depth_3"><a aria-current="page" href="/docs/Java-develop/Redis.html#redis-服务器关闭" class="router-link-active router-link-exact-active link page-catalog-item" aria-label="redis 服务器关闭"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->redis 服务器关闭<!--]--></span></span><!--[--><!--]--></a></li><!--]--><!--[--><li class="page-catalog-menu-depth_3"><a aria-current="page" href="/docs/Java-develop/Redis.html#redis-数据库" class="router-link-active router-link-exact-active link page-catalog-item" aria-label="Redis 数据库"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->Redis 数据库<!--]--></span></span><!--[--><!--]--></a></li><!--]--><!--[--><li class="page-catalog-menu-depth_3"><a aria-current="page" href="/docs/Java-develop/Redis.html#redis单线程模型" class="router-link-active router-link-exact-active link page-catalog-item" aria-label="redis单线程模型"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->redis单线程模型<!--]--></span></span><!--[--><!--]--></a></li><!--]--><!--]--><!--[--><li class="page-catalog-menu-depth_2"><a aria-current="page" href="/docs/Java-develop/Redis.html#redis数据类型指令" class="router-link-active router-link-exact-active link page-catalog-item" aria-label="Redis数据类型指令"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->Redis数据类型指令<!--]--></span></span><!--[--><!--]--></a></li><!--[--><li class="page-catalog-menu-depth_3"><a aria-current="page" href="/docs/Java-develop/Redis.html#string-字符串" class="router-link-active router-link-exact-active link page-catalog-item" aria-label="string（字符串）"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->string（字符串）<!--]--></span></span><!--[--><!--]--></a></li><!--]--><!--[--><li class="page-catalog-menu-depth_3"><a aria-current="page" href="/docs/Java-develop/Redis.html#hash-哈希" class="router-link-active router-link-exact-active link page-catalog-item" aria-label="Hash（哈希）"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->Hash（哈希）<!--]--></span></span><!--[--><!--]--></a></li><!--]--><!--[--><li class="page-catalog-menu-depth_3"><a aria-current="page" href="/docs/Java-develop/Redis.html#list-列表" class="router-link-active router-link-exact-active link page-catalog-item" aria-label="list（列表）"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->list（列表）<!--]--></span></span><!--[--><!--]--></a></li><!--]--><!--[--><li class="page-catalog-menu-depth_3"><a aria-current="page" href="/docs/Java-develop/Redis.html#set-集合" class="router-link-active router-link-exact-active link page-catalog-item" aria-label="Set（集合）"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->Set（集合）<!--]--></span></span><!--[--><!--]--></a></li><!--]--><!--[--><li class="page-catalog-menu-depth_3"><a aria-current="page" href="/docs/Java-develop/Redis.html#zset-有序集合" class="router-link-active router-link-exact-active link page-catalog-item" aria-label="zset(有序集合)"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->zset(有序集合)<!--]--></span></span><!--[--><!--]--></a></li><!--]--><!--]--><!--[--><li class="page-catalog-menu-depth_2"><a aria-current="page" href="/docs/Java-develop/Redis.html#redis配置文件-参数" class="router-link-active router-link-exact-active link page-catalog-item" aria-label="redis配置文件-参数"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->redis配置文件-参数<!--]--></span></span><!--[--><!--]--></a></li><!--]--><!--[--><li class="page-catalog-menu-depth_2"><a aria-current="page" href="/docs/Java-develop/Redis.html#redis持久化" class="router-link-active router-link-exact-active link page-catalog-item" aria-label="redis持久化"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->redis持久化<!--]--></span></span><!--[--><!--]--></a></li><!--[--><li class="page-catalog-menu-depth_3"><a aria-current="page" href="/docs/Java-develop/Redis.html#_8-1-rdb-redis-database" class="router-link-active router-link-exact-active link page-catalog-item" aria-label="8.1 RDB（Redis DataBase）"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->8.1 RDB（Redis DataBase）<!--]--></span></span><!--[--><!--]--></a></li><!--]--><!--[--><li class="page-catalog-menu-depth_3"><a aria-current="page" href="/docs/Java-develop/Redis.html#_8-3-持久化方案选择" class="router-link-active router-link-exact-active link page-catalog-item" aria-label="8.3 持久化方案选择"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->8.3 持久化方案选择<!--]--></span></span><!--[--><!--]--></a></li><!--]--><!--[--><li class="page-catalog-menu-depth_3"><a aria-current="page" href="/docs/Java-develop/Redis.html#_8-4-rdb-aof混合持久化" class="router-link-active router-link-exact-active link page-catalog-item" aria-label="8.4 RDB-AOF混合持久化"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->8.4 RDB-AOF混合持久化<!--]--></span></span><!--[--><!--]--></a></li><!--]--><!--]--><!--[--><li class="page-catalog-menu-depth_2"><a aria-current="page" href="/docs/Java-develop/Redis.html#redis主从复制" class="router-link-active router-link-exact-active link page-catalog-item" aria-label="Redis主从复制"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->Redis主从复制<!--]--></span></span><!--[--><!--]--></a></li><!--]--><!--[--><li class="page-catalog-menu-depth_2"><a aria-current="page" href="/docs/Java-develop/Redis.html#redis-和-boot-新整合" class="router-link-active router-link-exact-active link page-catalog-item" aria-label="Redis 和 Boot 新整合"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->Redis 和 Boot 新整合<!--]--></span></span><!--[--><!--]--></a></li><!--[--><li class="page-catalog-menu-depth_3"><a aria-current="page" href="/docs/Java-develop/Redis.html#基础配置" class="router-link-active router-link-exact-active link page-catalog-item" aria-label="基础配置"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->基础配置<!--]--></span></span><!--[--><!--]--></a></li><!--]--><!--[--><li class="page-catalog-menu-depth_3"><a aria-current="page" href="/docs/Java-develop/Redis.html#template-方式数据读写" class="router-link-active router-link-exact-active link page-catalog-item" aria-label="Template 方式数据读写"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->Template 方式数据读写<!--]--></span></span><!--[--><!--]--></a></li><!--]--><!--]--><!--[--><li class="page-catalog-menu-depth_2"><a aria-current="page" href="/docs/Java-develop/Redis.html#redis-和-sping-boot-整合" class="router-link-active router-link-exact-active link page-catalog-item" aria-label="redis 和 sping boot 整合"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->redis 和 sping boot 整合<!--]--></span></span><!--[--><!--]--></a></li><!--[--><li class="page-catalog-menu-depth_3"><a aria-current="page" href="/docs/Java-develop/Redis.html#template方式" class="router-link-active router-link-exact-active link page-catalog-item" aria-label="Template方式"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->Template方式<!--]--></span></span><!--[--><!--]--></a></li><!--]--><!--[--><li class="page-catalog-menu-depth_3"><a aria-current="page" href="/docs/Java-develop/Redis.html#redis-repositories方式" class="router-link-active router-link-exact-active link page-catalog-item" aria-label="Redis Repositories方式"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->Redis Repositories方式<!--]--></span></span><!--[--><!--]--></a></li><!--]--><!--]--><!--[--><li class="page-catalog-menu-depth_2"><a aria-current="page" href="/docs/Java-develop/Redis.html#redis的缓存失效问题" class="router-link-active router-link-exact-active link page-catalog-item" aria-label="redis的缓存失效问题"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->redis的缓存失效问题<!--]--></span></span><!--[--><!--]--></a></li><!--[--><li class="page-catalog-menu-depth_3"><a aria-current="page" href="/docs/Java-develop/Redis.html#_1、缓存雪崩" class="router-link-active router-link-exact-active link page-catalog-item" aria-label="1、缓存雪崩"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->1、缓存雪崩<!--]--></span></span><!--[--><!--]--></a></li><!--]--><!--[--><li class="page-catalog-menu-depth_3"><a aria-current="page" href="/docs/Java-develop/Redis.html#_2、缓存穿透" class="router-link-active router-link-exact-active link page-catalog-item" aria-label="2、缓存穿透"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->2、缓存穿透<!--]--></span></span><!--[--><!--]--></a></li><!--]--><!--[--><li class="page-catalog-menu-depth_3"><a aria-current="page" href="/docs/Java-develop/Redis.html#_3、缓存击穿" class="router-link-active router-link-exact-active link page-catalog-item" aria-label="3、缓存击穿"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->3、缓存击穿<!--]--></span></span><!--[--><!--]--></a></li><!--]--><!--]--><!--[--><li class="page-catalog-menu-depth_2"><a aria-current="page" href="/docs/Java-develop/Redis.html#缓存与数据库一致性" class="router-link-active router-link-exact-active link page-catalog-item" aria-label="缓存与数据库一致性"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->缓存与数据库一致性<!--]--></span></span><!--[--><!--]--></a></li><!--[--><li class="page-catalog-menu-depth_3"><a aria-current="page" href="/docs/Java-develop/Redis.html#cache-aside-pattern" class="router-link-active router-link-exact-active link page-catalog-item" aria-label="Cache Aside Pattern"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->Cache Aside Pattern<!--]--></span></span><!--[--><!--]--></a></li><!--]--><!--[--><li class="page-catalog-menu-depth_3"><a aria-current="page" href="/docs/Java-develop/Redis.html#双写读写并发问题" class="router-link-active router-link-exact-active link page-catalog-item" aria-label="双写读写并发问题"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->双写读写并发问题<!--]--></span></span><!--[--><!--]--></a></li><!--]--><!--[--><li class="page-catalog-menu-depth_3"><a aria-current="page" href="/docs/Java-develop/Redis.html#cache-aside-pattern-方案" class="router-link-active router-link-exact-active link page-catalog-item" aria-label="Cache Aside Pattern 方案"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->Cache Aside Pattern 方案<!--]--></span></span><!--[--><!--]--></a></li><!--]--><!--[--><li class="page-catalog-menu-depth_3"><a aria-current="page" href="/docs/Java-develop/Redis.html#cap-方案的改进" class="router-link-active router-link-exact-active link page-catalog-item" aria-label="CAP 方案的改进"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->CAP 方案的改进<!--]--></span></span><!--[--><!--]--></a></li><!--]--><!--]--><!--[--><li class="page-catalog-menu-depth_2"><a aria-current="page" href="/docs/Java-develop/Redis.html#redis-redisson-锁-分布式锁" class="router-link-active router-link-exact-active link page-catalog-item" aria-label="Redis/Redisson 锁 | 分布式锁"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->Redis/Redisson 锁 | 分布式锁<!--]--></span></span><!--[--><!--]--></a></li><!--[--><li class="page-catalog-menu-depth_3"><a aria-current="page" href="/docs/Java-develop/Redis.html#分布式锁使用场景" class="router-link-active router-link-exact-active link page-catalog-item" aria-label="分布式锁使用场景"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->分布式锁使用场景<!--]--></span></span><!--[--><!--]--></a></li><!--]--><!--[--><li class="page-catalog-menu-depth_3"><a aria-current="page" href="/docs/Java-develop/Redis.html#redis-锁" class="router-link-active router-link-exact-active link page-catalog-item" aria-label="Redis 锁"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->Redis 锁<!--]--></span></span><!--[--><!--]--></a></li><!--]--><!--[--><li class="page-catalog-menu-depth_3"><a aria-current="page" href="/docs/Java-develop/Redis.html#redisson-锁" class="router-link-active router-link-exact-active link page-catalog-item" aria-label="Redisson 锁"><!--[--><!--]--><span class="xicon-container left"><!--[--><!----><!--]--><span class="xicon-content" style="color:inherit;font-size:14px;"><!--[-->Redisson 锁<!--]--></span></span><!--[--><!--]--></a></li><!--]--><!--]--><!--]--></ul></div></div></div></div><!----><!----><!--]--></div>
    <script type="module" src="/assets/app-8a43a0f0.js" defer></script>
  </body>
</html>
